関数の種類によって異なります:
- <リ>
関数がインライン テーブル値関数である場合、この関数は "パラメーター化された" ビューであり、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.
プレ>