sql >> Database >  >> RDS >> Sqlserver

Prestaties van buiten gelden met functie

Het hangt af van het functietype:

  1. Als de functie een inline-tabelwaardefunctie is, wordt deze functie beschouwd als een "geparametriseerde" weergave en SQL Server kan wat optimalisatiewerk doen.

  2. Als de functie een tabelwaardefunctie met meerdere stappen is, is het moeilijk voor SQL Server om de verklaring en de uitvoer van SET STATISTICS IO . te optimaliseren zal misleidend zijn.

Voor de volgende test gebruikte ik de AdventureWorks2008 (u kunt deze database downloaden van CodePlex). In deze voorbeelddatabase vindt u mogelijk een inline table-valued function genaamd [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

Ik heb een nieuwe functie gemaakt met de naam [Sales].[ufnGetCheapestProductMultiStep] . Deze functie is een 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 kunnen we de volgende tests uitvoeren:

--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

En dit is de uitvoer van SQL Profiler :

Conclusie :u kunt dat zien met behulp van een query of een inline tabelwaardefunctie met OUTER APPLY geeft u dezelfde prestaties (logische uitlezingen). Plus:de functies met tabelwaarde met meerdere stappen zijn (meestal) duurder .

Opmerking :Ik raad het gebruik van SET STATISTICS IO af om de IO te meten voor scalaire en meerstaps tabelwaardefuncties omdat de resultaten verkeerd kunnen zijn. Voor deze tests is bijvoorbeeld de uitvoer van SET STATISTICS IO ON zal zijn:

--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. chmod mislukt:EPERM (bewerking niet toegestaan) in Android?

  2. In Oracle SQL:Hoe voeg je de huidige datum + tijd in een tabel in?

  3. MySQL, utf8_general_ci &cyrillische tekens

  4. Hoe verbind je Django met een MySQL-database via een SSL-verbinding?