sql >> Databasteknik >  >> RDS >> Sqlserver

Prestanda av yttre applicera med funktion

Det beror på funktionstyp:

  1. Om funktionen är en inline-tabellvärderad funktion kommer denna funktion att anses vara en "parameteriserad" vy och SQL Server kan göra en del optimeringsarbete.

  2. Om funktionen är flerstegstabellvärdad funktion är det svårt för SQL Server för att optimera satsen och utdata från SET STATISTICS IO kommer att vara vilseledande.

För nästa test använde jag AdventureWorks2008 (du kan ladda ner denna databas från CodePlex). I denna exempeldatabas kan du hitta en inline table-valued function heter [Sales].[ufnGetCheapestProduct] :

ALTER FUNCTION [Sales].[ufnGetCheapestProduct](@ProductID INT)
RETURNS TABLE
AS
RETURN
    SELECT   dt.ProductID
            ,dt.UnitPrice
    FROM
    (
        SELECT   d.SalesOrderDetailID
                ,d.UnitPrice
                ,d.ProductID  
                ,ROW_NUMBER() OVER(PARTITION BY d.ProductID ORDER BY d.UnitPrice ASC, d.SalesOrderDetailID) RowNumber
        FROM    Sales.SalesOrderDetail d
        WHERE   d.ProductID = @ProductID
    ) dt
    WHERE   dt.RowNumber = 1

Jag skapade en ny funktion som heter [Sales].[ufnGetCheapestProductMultiStep] . Denna funktion är en multi-step table-valued function :

CREATE FUNCTION [Sales].[ufnGetCheapestProductMultiStep](@ProductID INT)
RETURNS @Results TABLE (ProductID INT PRIMARY KEY, UnitPrice MONEY NOT NULL)
AS
BEGIN
    INSERT  @Results(ProductID, UnitPrice)
    SELECT   dt.ProductID
            ,dt.UnitPrice
    FROM
    (
        SELECT   d.SalesOrderDetailID
                ,d.UnitPrice
                ,d.ProductID  
                ,ROW_NUMBER() OVER(PARTITION BY d.ProductID ORDER BY d.UnitPrice ASC, d.SalesOrderDetailID) RowNumber
        FROM    Sales.SalesOrderDetail d
        WHERE   d.ProductID = @ProductID
    ) dt
    WHERE   dt.RowNumber = 1;

    RETURN;
END

Nu kan vi köra nästa test:

--Test 1
SELECT  p.ProductID, p.Name, oa1.*
FROM    Production.Product p
OUTER APPLY 
(
    SELECT   dt.ProductID
            ,dt.UnitPrice
    FROM
    (
        SELECT   d.SalesOrderDetailID
                ,d.UnitPrice
                ,d.ProductID  
                ,ROW_NUMBER() OVER(PARTITION BY d.ProductID ORDER BY d.UnitPrice ASC, d.SalesOrderDetailID) RowNumber
        FROM    Sales.SalesOrderDetail d
        WHERE   d.ProductID = p.ProductID
    ) dt
    WHERE   dt.RowNumber = 1
) oa1

--Test 2
SELECT  p.ProductID, p.Name, oa2.*
FROM    Production.Product p
OUTER APPLY [Sales].[ufnGetCheapestProduct](p.ProductID) oa2

--Test 3
SELECT  p.ProductID, p.Name, oa3.*
FROM    Production.Product p
OUTER APPLY [Sales].[ufnGetCheapestProductMultiStep](p.ProductID) oa3

Och detta är utdata från SQL Profiler :

Slutsats :du kan se att du använder en fråga eller en inline-tabellvärderad funktion med OUTER APPLY ger dig samma prestanda (logiska läsningar). Plus:de flerstegstabellvärderade funktionerna är (vanligtvis) dyrare .

Obs :Jag rekommenderar inte att du använder SET STATISTICS IO för att mäta IO för skalära och flerstegstabellvärderade funktioner eftersom resultaten kan vara felaktiga. Till exempel, för dessa tester utdata från SET STATISTICS IO ON kommer att vara:

--Test 1
Table 'SalesOrderDetail'. Scan count 504, logical reads 1513, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

--Test 2
Table 'SalesOrderDetail'. Scan count 504, logical reads 1513, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

--Test 3
Table '#064EAD61'. Scan count 504, logical reads 1008 /*WRONG*/, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


  1. SQL Server:Vad är skillnaden mellan CROSS JOIN och FULL OUTER JOIN?

  2. Problem med mysql gem på osx 10.6.8

  3. Underfrågor i kontrollbegränsning

  4. Laravel Kan inte ta bort eller uppdatera en överordnad rad:en begränsning av främmande nyckel misslyckas