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