我正在比较 mssql 中的两个查询,并尝试确定一个查询是否实际上比另一个查询效率更高。我正在使用 Microsoft 的 AdventureWorks2016 示例数据库。 https://learn.microsoft.com/en-us/sql/samples/adventureworks-install-configure?view=sql-server-ver16&tabs=ssms
在一个查询中,我使用一个函数创建一个表,该表带有在连接中使用的索引。第二个查询是使用子查询来替换函数。
create function departmentSummary()
returns @tmp Table (
DepartmentID int,
NumEmployees int,
primary key (DepartmentID)
)
as
begin
insert into @tmp
select DepartmentID, count(*)
from [HumanResources].[EmployeeDepartmentHistory]
where EndDate is null
group by DepartmentID;
return
end;
go;
select a.*, b.NumEmployees
from [HumanResources].[Department] as a
join dbo.departmentSummary() as b on a.DepartmentID=b.DepartmentID
;
select a.*, b.NumEmployees
from [HumanResources].[Department] as a
join (
select DepartmentID, count(*) NumEmployees
from [HumanResources].[EmployeeDepartmentHistory]
where EndDate is null
group by DepartmentID
) as b on a.DepartmentID=b.DepartmentID
;
执行计划显示使用该函数的查询成本要低得多。我想知道该函数所做的所有工作实际上是否包含在成本中,或者连接的索引是否产生了那么大的影响。
在比较子树成本时应该非常谨慎。
它们并非旨在用于评估潜在绩效,即使 处于“高水平”。该模型是一个恰好可以工作的抽象 相当适合其设计的内部用途。这 估计成本与实际成本有明显相似之处的可能性 您的硬件和配置的执行成本非常小 确实如此。
根据实际情况选择其他指标来比较性能 问题对你来说很重要。
即使在这些参数内,TVF 的成本也不比没有的查询便宜。 SSMS 只是不会向您显示在多语句 TVF 本身内运行的查询的执行计划,并且不会从
[HumanResources].[EmployeeDepartmentHistory]
进行选择并插入到 @tmp
。此成本也没有反映在“表值函数”运算符的成本中。
如果它确实向您展示了这一点,则完整图片将如下所示 - 查询的两个语句与多语句 TVF 总计占批处理成本的 60%。
该功能的计划与没有计划的绿色突出显示部分非常相似。因此,它们做的事情大致相同,但该函数有一些额外的开销,需要将分组的行插入到表变量中,而不是立即继续针对
Department
进行相关查找。
顺便说一句:对于这个答案,我启动了探查器并使用“Showplan XML 统计配置文件”事件来获取 SSMS 未显示的缺失的实际执行计划。通过使用 XEvents 捕获执行计划,可以以更少弃用且性能更好的方式实现同样的效果。