【发布时间】: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 生成。
标签: sql sql-server query-optimization self-join