0

我有两个非常大的多选查询。所有选择都已加入(左、内和右连接)。例子:

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 倍。你知道为什么吗 ?

4

2 回答 2

1

你的两个查询不一样。第一个是将部分结果存储在表变量中。第二个是将其包含在查询中。

执行计划几乎必然不同。要了解这些差异,您需要查看查询计划。

以下是性能可能与您的预期不同的一些可能原因:

  • 也许从数据库返回行的开销比插入表的开销要大。
  • SQL查询在编译时可能有更多关于表变量的信息,因为表变量在第二部分编译时已经创建。
  • 即使更新了所有统计信息,组合查询也可能只是选择了一个糟糕的执行计划。也就是说,一起执行“P2”查询可能是最优的,但它可能会选择另一个计划。
于 2013-06-07T00:56:15.847 回答
1

您没有提供很多信息,因此我的回答将非常笼统。

当 SQL Server 优化查询时,它会尝试找到可能的最佳执行计划。但是,对于复杂的查询,可能的计划数量如此之多,以至于不可能进行详尽的搜索。

如果您查看一个简单的两表连接,就像SELECT * FROM A JOIN B ON A.id = B.id;您有 6 个选项来创建计划:

  • A 循环连接 B
  • A 合并连接 B
  • 哈希连接 B
  • B 循环连接 A
  • B 合并加入 A
  • B 哈希连接 A

这甚至没有考虑不同的表访问操作符,如索引查找或扫描。如果表上有多个索引,它会变得更加复杂。(有关不同连接类型和连接运算符的更多信息,请查看我的连接系列: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 通常会更好,因此使用它们可能会损害下一步。

于 2013-06-07T00:59:19.887 回答