我有几个使用外部应用的存储过程。外部apply中的查询总是相同的,所以我可以构建一个公用表值函数,这给了我重复使用代码的明显好处,但是我想知道是否存在性能影响。如果我打电话给某个功能,我会受到打击吗?
例如:
SELECT
m.[ID],
m.[MyField],
o.[OtherField]
FROM
[MyTable] m
OUTER Apply
(
fMyFunction(m.[ID])
)
VS
SELECT
mt.[ID],
mt.[MyField],
o.[OtherField]
FROM
[MyTable] mt
OUTER Apply
(
SELECT TOP 1
ot.[OtherField]
FROM
[OtherTable] ot
WHERE
ot.[ID] = m.[ID]
) o
答案 0 :(得分:3)
取决于功能类型:
1)如果函数是内联表值函数,则该函数将被视为“参数化”视图,SQL Server
可以进行一些优化工作。
2)如果函数是多步表值函数,则SQL Server
很难优化语句,SET STATISTICS IO
的输出会产生误导。
对于下一个测试,我使用了AdventureWorks2008
(您可以从CodePlex下载此数据库)。在此示例数据库中,您可能会找到名为inline table-valued function
的{{1}}:
[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
的查询或内联表值函数将为您提供相同的性能(逻辑读取)。另外:the multi-step table-valued functions are (usually) more expensive。
注意:我不建议使用OUTER APPLY
来衡量标量和多步表值函数的SET STATISTICS IO
,因为结果可能有误。例如,对于这些测试,IO
的输出将为:
SET STATISTICS IO ON
表'产品'。扫描计数1,逻辑读取5,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
答案 1 :(得分:1)
Outer Apply
不应该在这里考虑......
<强>原因强>
它将迭代MyTable
的每个记录,并将搜索Outer Apply
表中的相应记录,尽管您将从MyTable获取所有记录。所以它应该用Join(Left / Inner)代替。这将加快查询速度,尤其是当您要获取大量记录时。