带有子行的 T-SQL SELECT 存在优化
Posted
技术标签:
【中文标题】带有子行的 T-SQL SELECT 存在优化【英文标题】:T-SQL SELECT with child rows exists optimise 【发布时间】:2011-08-29 09:32:34 【问题描述】:我正在尝试优化我的查询。基本上我有一个部门表和一个文档表。每个文档属于一个部门,每个文档可以是特定类型。
目前 mu 查询看起来像这样
SELECT DepartmentID,
[Description] = DepartmentNo + ' (' + DepartmentName + ')',
hasInvoice = CASE WHEN EXISTS(SELECT DocID FROM Document WHERE DepartmentID = Department.DepartmentID AND TypeID = 1) > 0 THEN 1 ELSE 0 END,
hasCreditNote = CASE WHEN EXISTS(SELECT DocID FROM Document WHERE DepartmentID = Department.DepartmentID AND TypeID = 2) > 0 THEN 1 ELSE 0 END,
hasQuote = CASE WHEN EXISTS(SELECT DocID FROM Document WHERE DepartmentID = Department.DepartmentID AND TypeID = 3) > 0 THEN 1 ELSE 0 END
FROM Department
ORDER BY DepartmentName
我遇到的问题是,每次按类型查找与部门相关的文档都会导致查询重新扫描文档表,这使得事情变得非常缓慢。有没有更优化的方法来做到这一点?我尝试使用 CTE,为每种类型进行左连接。但它似乎对加快查询速度没有影响。
我们有大约 200000 个文档,因此优化此查询非常重要。
谢谢
【问题讨论】:
你在桌子上设置了哪些索引? 是的。它不应该“重新扫描”。执行计划是否真的显示了这一点?理想情况下,您希望在Document(DepartmentID,TypeID)
上有一个复合索引
【参考方案1】:
无论索引是什么,您对 Document 表的“触摸”太多:Department 表中每行 3 次。所以它的扩展性会很差,优化器可能不会将相关的子查询更改为 JOIN。
您可以像这样使用 JOIN 对 Document 表进行一次“触摸”
SELECT
D.DepartmentID,
[Description] = D.DepartmentNo + ' (' + D.DepartmentName + ')',
hasInvoice = SIGN(COUNT(CASE WHEN doc.TypeID = 1 THEN 1 END)),
hasCreditNote = SIGN(COUNT(CASE WHEN doc.TypeID = 2 THEN 1 END)),
hasQuote = SIGN(COUNT(CASE WHEN doc.TypeID = 3 THEN 1 END))
FROM
Department D
LEFT JOIN
Document doc ON D.DepartmentID = doc.DepartmentID
ORDER BY
D.DepartmentName, D.DepartmentID, D.DepartmentNo
您也可以在过滤+聚合的 Document 派生表上 LEFT JOIN 3 次或使用 CROSS APPLY 3 次:但这些仍然是 Document 表的 3 次使用
对于任何解决方案,您都需要在文档中的 DepartmentID, TypeID
上建立索引。没有这个,我只有re-arranged the deck chairs可以这么说
我假设 Department.DepartmentID 也是一个聚集索引。
【讨论】:
以上是关于带有子行的 T-SQL SELECT 存在优化的主要内容,如果未能解决你的问题,请参考以下文章