我有两个非常大的查询,有多个选择。所有选择都是 JOINED (左,内和右连接)。例如:
Declare @p2 Table (
...
)
Insert into @p2
Select * from D
join E on D.id = E.id
left join F on E.id2 = F.id
....
Select * from(
(Select * from A
join B on A.id = B.id
join C on B.id2 = C.id
....
) as PART1
right join
@p2 as PART2
on PART1.ID = PART2.ID)
此代码工作正常,需要大约20秒才能执行。我运行执行计划,它显示57%的时间用于插入。为了优化此查询,我创建了一个查询,如:
Select * from(
(Select * from A
join B on A.id = B.id
join C on B.id2 = C.id
....
) as PART1
right join
(Select * from D
join E on D.id = E.id
left join F on E.id2 = F.id
....) as PART2
on PART1.ID = PART2.ID)
我预计这会显着提高速度,但结果却慢了4倍。你知道为什么吗?
答案 0 :(得分:1)
你的两个问题不一样。第一种是将结果的一部分存储在表变量中。第二个是将它包含在查询中。
执行计划几乎必然不同。要了解这些差异,您需要查看查询计划。
以下是可能导致性能与预期不同的一些原因:
答案 1 :(得分:1)
你没有提供很多信息,所以我的回答非常一般。
当SQL Server优化查询时,它会尝试查找最佳的可执行执行计划。但是,对于复杂查询,可能的计划数量如此之高,以至于无法进行详尽的搜索。
如果您查看一个简单的两个表连接,例如SELECT * FROM A JOIN B ON A.id = B.id;
,您有6个选项来创建计划:
这甚至不考虑索引搜索或扫描等不同的表访问操作符。如果表上有多个索引,则会比这更复杂。 (有关不同联接类型和联接运算符的详细信息,请查看我的联接系列:http://sqlity.net/en/1146/a-join-a-day-introduction/)
现在,如果A,B,C之间有三个表连接,则有六种方法可以对表进行排序,两种连接操作符有3种选项,每种方法共有54种方法来创建一个计划,只需查看连接运算符和表订购。这几乎增加了十倍。对于六个表,有近20万个选项,八个表几乎有1亿个。同样,这只是表顺序和连接运算符,并没有考虑潜在的索引和表访问方法。
SQL Server不是试图完成所有可能需要花费更长时间才能执行查询的计划,而是根据每个表数据的统计信息支持的启发式和规则来查看少数几个。这些启发式通常非常好,通常SQL Server会找到一个非常接近最佳可能的计划。但是,有一些情况是这个过程下降了。如果统计数据已过期,则特别容易发生这种情况。
因此,首先要看的是这些统计数据。如果这没有帮助,请尝试添加筛选的统计信息和筛选的索引。如果您在企业中,则可以创建索引视图以预先计算连接的某些内容。 (除非您明确说明,否则标准版不会使用索引视图。)
之后,您可以查看提供联接提示,以帮助SQL Server提出一个好的计划。
如果所有这些都无济于事,请将查询拆分为较小的部分,并将中间结果存储在临时对象中。在@table_variables没有统计信息的情况下,使用#temp_tables通常会更好,所以它们的使用会对下一步造成伤害。