sql >> Database teknologi >  >> RDS >> Sqlserver

Ydeevne af ydre anvende med funktion

Det afhænger af funktionstype:

  1. Hvis funktionen er en indlejret tabelværdieret funktion, vil denne funktion blive betragtet som en "parameteriseret" visning og SQL Server kan udføre noget optimeringsarbejde.

  2. Hvis funktionen er flertrins-tabelværdi-funktion, er det svært for SQL Server for at optimere sætningen og outputtet fra SET STATISTICS IO vil være vildledende.

Til den næste test brugte jeg AdventureWorks2008 (du kan downloade denne database fra CodePlex). I denne eksempeldatabase kan du finde en inline table-valued function navngivet [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
 

Jeg oprettede en ny funktion ved navn [Sales].[ufnGetCheapestProductMultiStep] . Denne funktion er 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øre de næste 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

Og dette er output fra SQL Profiler :

Konklusion :du kan se, at du bruger en forespørgsel eller en indlejret tabelværdi-funktion med OUTER APPLY vil give dig den samme ydeevne (logiske læsninger). Plus:de flertrins-tabelvurderede funktioner er (normalt) dyrere .

Bemærk :Jeg anbefaler ikke at bruge SET STATISTICS IO for at måle IO for skalar- og flertrinstabelværdier, fordi resultaterne kan være forkerte. For disse tests for eksempel output fra SET STATISTICS IO ON vil være:

--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. Tving MySQL til at returnere dubletter fra WHERE IN-klausulen uden at bruge JOIN/UNION?

  2. Migrer data og skema fra MySQL til SQL Server

  3. Mysql Hvordan opretter du et clustered index?

  4. Kan vi slette den fysiske fil fra serveren, når jeg sletter den tilsvarende post fra databasen?