SQL server连接选择比使用本地表连接选择慢

SQL server连接选择比使用本地表连接选择慢,sql,sql-server-2008,query-optimization,Sql,Sql Server 2008,Query Optimization,我有两个非常大的查询,有多个选择。所有选择都是连接的(左、内和右连接)。例如: 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

我有两个非常大的查询,有多个选择。所有选择都是连接的(左、内和右连接)。例如:

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

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

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

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

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

    • 你没有提供太多的信息,所以我的回答将非常笼统

      当SQL Server优化查询时,它会尝试找到可能的最佳执行计划。然而,对于复杂的查询,可能的计划数量非常多,因此不可能进行彻底的搜索

      如果您查看一个简单的两表联接,如
      SELECT*FROM a join B ON a.id=B.id创建计划有6个选项:

      • A循环连接B
      • A合并加入B
      • A散列连接B
      • B循环连接A
      • 合并加入
      • B散列加入A
      这甚至不能解释不同的表访问操作符,如索引查找或扫描。如果表上有多个索引,则会变得更加复杂。(有关不同联接类型和联接运算符的详细信息,请查看我的联接系列:)

      现在,如果在a、B、C之间有一个三表联接,那么有六种方法可以对表进行排序,两个联接运算符有三个选项,每个选项总共有54种方法可以创建一个计划,只需查看联接运算符和表顺序即可。这几乎增加了十倍。六张桌子有近20万个选项,八张桌子有近1亿个选项。同样,这只是表顺序和联接运算符,不考虑潜在的索引和表访问方法

      SQL Server没有尝试检查所有计划(这些计划可能比实际执行查询花费的时间长得多),而是根据每个表数据的统计信息支持的启发式和规则只查看少数计划。这些启发式方法通常都非常好,通常SQLServer会找到一个非常接近最佳方案的方案。然而,也有一些案例表明这一过程是显而易见的。如果统计数据过时,这种情况尤其可能发生

      因此,首先要看的是这些统计数据。如果这没有帮助,请尝试添加筛选的统计信息和筛选的索引。如果您在enterprise上,您可以创建索引视图来预先计算一些连接。(标准版不会使用索引视图,除非您明确告知。)

      之后,您可以考虑提供连接提示来帮助SQLServer制定一个好的计划


      如果所有这些都没有帮助,请将查询拆分为更小的部分,并将中间结果存储在临时对象中。在@table_变量没有统计数据的情况下,使用#temp_表通常更好,因此它们的使用可能会影响下一步。

      感谢深入分析。我将尝试应用您的提示并发布结果。