[英]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.