SQL 查询性能下降取决于搜索值的顺序

Posted

技术标签:

【中文标题】SQL 查询性能下降取决于搜索值的顺序【英文标题】:SQL Query Performance Degrades Depending on the Order of the Search Values 【发布时间】:2012-05-15 18:33:42 【问题描述】:

我有一个双重自联接查询,其中在交换搜索值时性能会严重下降。

-- 500,000 i/o & 500ms execution
select
  fooA.ID
  , fooB.ID
from
  foo AS fooA
  INNER JOIN bar AS barA ON fooA.barID = barA.barID
  INNER JOIN foo AS fooB ON fooA.fooID = fooB.fooID -- self join
  INNER JOIN bar AS barB ON fooB.barID = barB.barID
where
  barA.value = 'xyz'
  AND barB.value = '60'

-- 5,000 i/o & 5ms execution
select
  fooA.ID
  , fooB.ID
from
  foo AS fooA
  INNER JOIN bar AS barA ON fooA.barID = barA.barID
  INNER JOIN foo AS fooB ON fooA.fooID = fooB.fooID -- self join
  INNER JOIN bar AS barB ON fooB.barID = barB.barID
where
  barA.value = '60'
  AND barB.value = 'xyz'
值“xyz”在“bar”表中列出了 150,000 次。 值“60”在“bar”表中列出了 500 次。 查询计划是相同的,只是最里面的循环返回 150,000 行或 500 行,具体取决于首先列出的搜索值。 搜索对非聚集索引执行搜索。 使用 FULLSCAN 更新了两个表的统计信息。

为什么 SQL 查询优化器不能正确识别在这两种情况下查询计划的最内层连接应该是行数最少的连接?

【问题讨论】:

使用限制查询中行数的条件最先出现。这是一般的经验法则。 可能的答案:查询参数化、参数嗅探和计划重用。 你能在 foo 和 bar 表上设置 ids 主键吗? @JonH 不幸的是,我没有选择确保哪个值首先出现。此查询由 Hibernate 生成。 【参考方案1】:

SQL Server 不会在每次执行查询时重新编译它。它只执行一次,并针对第一次看到的确切值进行了优化。我猜你缓存了一个不幸的计划。

尝试在末尾添加OPTION (RECOMPILE)

【讨论】:

我添加了这个,没有任何变化。对于两个查询计划,最内层连接的估计行数为 2,500,但实际差异很大。 这很奇怪。等式匹配索引的基数估计通常非常准确。您正在查找的表是否包含大量行且重复项很少? 我真的没有看到任何可能在这里造成麻烦的东西。能否贴出两个实际执行计划的截图? Image #1 是“坏”查询计划,Image #2 是“好”查询计划。 imgur.com/a/dv1ck 嗯我不知道这种行为的原因。潜在的解决方法:使用索引视图来实现其中一个连接。这将有助于 a) 将连接的运行时成本降低到几乎为零 b) 帮助行数估计(您需要手动在视图上创建统计信息)。索引视图是其应用查询的性能大锤。

以上是关于SQL 查询性能下降取决于搜索值的顺序的主要内容,如果未能解决你的问题,请参考以下文章

SQL CTE 性能是不是取决于声明顺序?

SQL Server 2008 - 连接导致性能下降

如何提高数据库查询的性能?

SQL Server 2005 - 内部联接的顺序

无论如何,为了提高 SQL 查询的性能,以按标签匹配计数查找具有顺序的行

SQL CTE性能是否取决于声明顺序?