sql >> データベース >  >> RDS >> Sqlserver

関数を使用した外部適用のパフォーマンス

    関数の種類によって異なります:

      <リ>

      関数がインライン テーブル値関数である場合、この関数は "パラメーター化された" ビューであり、SQL Server と見なされます。 最適化作業を行うことができます。

      <リ>

      関数が複数ステップのテーブル値関数である場合、SQL Server では難しい ステートメントと SET STATISTICS IO からの出力を最適化する 誤解を招く恐れがあります。

    次のテストでは、AdventureWorks2008 を使用しました (このデータベースは CodePlex からダウンロードできます)。このサンプル データベースには、inline table-valued functionがあります。 [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
      

    [Sales].[ufnGetCheapestProductMultiStep] という名前の新しい関数を作成しました .この関数は 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
      

    これで、次のテストを実行できます:

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

    これは SQL Profiler からの出力です :

    結論 :OUTER APPLY でクエリまたはインライン テーブル値関数を使用することがわかります。 同じパフォーマンスが得られます (論理読み取り)。プラス:複数ステップのテーブル値関数は (通常) 高価です .

    注意 :SET STATISTICS IO の使用はお勧めしません IO を測定する 結果が間違っている可能性があるため、スカラーおよびマルチステップのテーブル値関数の場合。たとえば、これらのテストでは、SET STATISTICS IO ON からの出力が になります:

    --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. Rails /ActiveRecordがOrderでPostgresSyntaxError非整数定数を提供するのはなぜですか?

    2. データベースからXMLに大量のデータを保存するにはどうすればよいですか(メモリの問題)?

    3. 外側のJOINの述語にLITERALを使用して2つの左結合がぶら下がっているORACLEは、左端のテーブルから行を除外します

    4. Oracle一括インポート