[英]Subquery Caching with Sql Server 2008
我正在使用Sql Server 2008创建存储过程,该存储过程将返回2个结果集。 与第二个查询一样,第一个查询返回一个我想重用的结果集作为子查询(请参见下面的示例)。 但是,由于第一个查询和子查询本质上返回相同的数据,所以我想知道是否可以使用某些缓存机制。 有可能这样做吗? 我正在尝试优化性能。
SELECT *
FROM Employees
WHERE BossId = 1
SELECT *
FROM CostCenters
WHERE EmployeeId IN (
SELECT EmployeeId
FROM Employees
WHERE BossId = 1
)
PS该示例是一个简化的问题。
您可以通过重用查询计划来缓存CTE。 这需要在该函数产生的结果集之间注入Eager Spool 。 Quassnoi在本文中使用了它 ,但目前无法找到更好的示例。 这是有关Eager Spool的另一本好书 。
据我所知,您将需要为此使用临时表或表变量。 这是两者的比较 。
下面使用OUTPUT子句填充表变量,并在一条语句中从中选择。
declare @MatchingResults table
(
EmployeeId int primary key --Other Columns
)
INSERT INTO @MatchingResults
OUTPUT INSERTED.*
SELECT EmployeeId --Other Columns
FROM Employees
WHERE BossId = 1
SELECT *
FROM CostCenters
WHERE EmployeeId IN (
SELECT EmployeeId
@MatchingResults))
表变量是最佳选择。 您还可以通过对子查询使用exists
运算符来提高性能,而不是in
:
-- obviously the columns should match your Employees table
declare @results table (
employeeId int,
column1 varchar,
column2 int
)
insert into @results
select * from Employees
where BossId = 1
-- using exists/not exists performs much better than in
select * from CostCenters
where exists ( select 0
from @results as r
where CostCenters.employeeId = r.employeeId )
缓存第一个查询的数据可能不会导致更好的性能。 SQL Server收到查询后,将其分解为简单的步骤,选择适当的索引和运算符,然后使用这些索引检索数据。 通过将第一个查询的数据存储在表变量或临时表中,可以防止SQL Server使用Employees表上的任何索引。
如果使用JOIN将查询重写为等效查询,则更容易了解会发生什么情况
SELECT c.*
FROM CostCenters c INNER JOIN Employees e on c.EmployeeId=e.EmployeeId
WHERE e.BossId=1
当SQL Server看到此查询时,它将检查表的统计信息。 如果BossId是高度选择性索引的列,则它可能首先尝试以此过滤。 否则,它将使用EmployeeId列上的任何索引将两个表中的行限制为最小值,然后使用BossId查找正确的行并返回它们。
索引的筛选操作非常快,因为索引仅包含行数据的一个子集,更易于缓存在内存中,并且具有允许快速搜索的物理结构。
在遇到实际的性能问题之前,您真的不应该尝试猜测SQL Server的查询优化器。 大多数时候,您会阻止它选择最佳的执行计划,从而导致性能下降
我能想到的最好的解决方案是选择CTE
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.