我有一个大型查询,其中一个简单的子查询优化将其从 8 分钟缩短到 20 秒。我不确定我是否理解为什么优化会产生如此巨大的效果。
本质上,这是问题部分:
SELECT (bunch of stuff)
FROM
a LEFT OUTER JOIN b ON a.ID = b.a
LEFT OUTER JOIN c ON b.ID = c.b
...
...
INNER JOIN veryLargeTable
ON a.ID = veryLargeTable.a
AND veryLargeTable.PetID =
(SELECT id from Pets WHERE Pets.Name = 'Something') /* BAD! */
...
...
总共有 16 个连接表。如果我替换第二个谓词veryLargeTable
与包含 petID 的预填充变量连接(而不是使用子查询)整个查询速度加快戏剧性地:
AND veryLargeTable.PetID = @petID /* Awesome! */
明显地,(SELECT id from Pets WHERE Name = 'Something')
正在为每一行执行。有两件事我不完全理解:
据我所知,这是一个不相关的子查询。 Pets 表根本不是外部查询的一部分。非相关子查询不是独立评估(并因此优化)的吗?为什么这里的情况不是这样呢?
执行计划截然不同。在失败的情况下(上面),整个子树处理估计 950k 行。在获胜的情况下(使用变量而不是子查询),估计只有大约 125k 行。这是怎么回事?如果存在该子查询,为什么会涉及这么多行? Pets.Name 列肯定有唯一的数据(但据我所知没有唯一的约束)。
请注意,正如我所期望的那样,将谓词移至 WHERE 子句不会影响任何一种情况下的查询,因为它是 INNER JOIN。
见解赞赏!
根据我的经验,查询越复杂,SQL 优化器创建灵活计划的能力就越差。这里你有 16 个连接,一些或大部分是外部连接,你至少有一个子查询......扔进足够的索引,基数,视图,外部应用,谁知道还有什么,没有人,甚至微软都没有工程师*,可以找出统一、定期生成最佳计划的例程。
你所描述的,我已经经历过很多次了——在混乱的查询中改变一件简单的事情,一切都会快一个数量级(或者,咬牙切齿,慢一些)。我没有办法确定什么时候复杂就太复杂了,这更多的是一种感觉。我的一般经验法则是,如果它看起来太长或太复杂,请尽可能简化 - 例如您预先选择的单个嵌套值,或者打破查询的一部分always使用小结果集快速运行,首先运行它并将结果存储在临时表中。
(*请注意,这是轻微的讽刺)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)