使用SQLServer2008进行子查询缓存

使用SQLServer2008进行子查询缓存,sql,tsql,sql-server-2008,Sql,Tsql,Sql Server 2008,我正在使用Sql Server 2008创建一个存储过程,它将返回2个结果集。第一个查询返回一个我希望在第二个查询中作为子查询继续使用的结果集(参见下面的示例)。但是,由于第一个查询和子查询基本上返回相同的数据,我想知道是否有一些缓存机制可以使用。有可能吗?我正在努力优化性能 SELECT * FROM Employees WHERE BossId = 1 SELECT * FROM CostCenters WHERE EmployeeId IN ( SELECT Em

我正在使用Sql Server 2008创建一个存储过程,它将返回2个结果集。第一个查询返回一个我希望在第二个查询中作为子查询继续使用的结果集(参见下面的示例)。但是,由于第一个查询和子查询基本上返回相同的数据,我想知道是否有一些缓存机制可以使用。有可能吗?我正在努力优化性能

SELECT * 
FROM   Employees
WHERE  BossId = 1

SELECT * 
FROM   CostCenters
WHERE  EmployeeId IN (
    SELECT EmployeeId 
    FROM   Employees
    WHERE  BossId = 1
)

另外,这个例子是一个简化的问题

据我所知,您需要为此使用临时表或表变量。A在这里

下面的语句使用该子句填充表变量,并在一条语句中从中进行选择

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))

据我所知,您需要为此使用临时表或表变量。A在这里

下面的语句使用该子句填充表变量,并在一条语句中从中进行选择

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))

我能想到的最好的解决办法是使用CTE


我能想到的最佳解决方案是使用CTE


表格变量是您的最佳选择。您还可以通过对子查询使用
exists
操作符而不是
中的
来提高性能:

-- 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 )

表变量是最好的选择。您还可以通过对子查询使用
exists
操作符而不是
中的
来提高性能:

-- 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 )

缓存第一个查询的数据可能不会产生更好的性能。当SQLServer接收到查询时,它会将其分解为简单的步骤,选择适当的索引和运算符,并使用这些索引检索数据。通过将第一个查询的数据存储在表变量或临时表中,可以防止SQL Server使用Employees表上的任何索引

如果使用JOIN将查询重写为其等价项,则更容易看到发生了什么

SELECT c.* 
FROM   CostCenters c INNER JOIN Employees e on c.EmployeeId=e.EmployeeId
WHERE e.BossId=1
当SQLServer看到此查询时,它将检查表的统计信息。如果BossId是一个高选择性索引列,它可能会首先尝试按此进行筛选。否则,它将使用EmployeeId列上的任何索引将两个表中的行限制到最小值,然后使用BossId查找正确的行并返回它们

索引上的筛选操作非常快,因为索引只包含行数据的子集,更容易在内存中缓存,并且具有允许快速搜索的物理结构


在遇到实际的性能问题之前,您确实不应该猜测SQL Server的查询优化器。大多数情况下,您会阻止它选择最佳执行计划,并导致性能下降

缓存第一个查询的数据可能不会带来更好的性能。当SQLServer接收到查询时,它会将其分解为简单的步骤,选择适当的索引和运算符,并使用这些索引检索数据。通过将第一个查询的数据存储在表变量或临时表中,可以防止SQL Server使用Employees表上的任何索引

如果使用JOIN将查询重写为其等价项,则更容易看到发生了什么

SELECT c.* 
FROM   CostCenters c INNER JOIN Employees e on c.EmployeeId=e.EmployeeId
WHERE e.BossId=1
当SQLServer看到此查询时,它将检查表的统计信息。如果BossId是一个高选择性索引列,它可能会首先尝试按此进行筛选。否则,它将使用EmployeeId列上的任何索引将两个表中的行限制到最小值,然后使用BossId查找正确的行并返回它们

索引上的筛选操作非常快,因为索引只包含行数据的子集,更容易在内存中缓存,并且具有允许快速搜索的物理结构


在遇到实际的性能问题之前,您确实不应该猜测SQL Server的查询优化器。大多数情况下,您会阻止它选择最佳执行计划,并导致性能下降

您可以通过重用查询计划来缓存CTE。这需要在函数生成的结果集之间注入,但我现在找不到更好的例子。还有一个。

您可以通过重用查询计划来缓存CTE。这需要在函数生成的结果集之间注入,但我现在找不到更好的例子。还有一个。

如何使用表变量?我是否将获得任何性能?请参阅编辑。是的,您可能会获得绩效,但请查看执行计划。有时,临时表在统计数据起作用的情况下可以表现得更好。如何使用表变量?我是否将获得任何性能?请参阅编辑。是的,您可能会获得绩效,但请查看执行计划。有时,临时表在统计数据起作用的情况下可以表现得更好。但这并没有实现(大多数情况下)。我也这么想,直到我纠正了我的错误,但这并没有成为现实(大多数时候)。在我纠正我之前,我也这么认为,您正在进行子缓存的查询有多贵?您正在进行子缓存的查询有多贵?