为什么这个(不相关的)子查询会导致这样的问题?

2024-03-08

我有一个大型查询,其中一个简单的子查询优化将其从 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')正在为每一行执行。有两件事我不完全理解:

  1. 据我所知,这是一个不相关的子查询。 Pets 表根本不是外部查询的一部分。非相关子查询不是独立评估(并因此优化)的吗?为什么这里的情况不是这样呢?

  2. 执行计划截然不同。在失败的情况下(上面),整个子树处理估计 950k 行。在获胜的情况下(使用变量而不是子查询),估计只有大约 125k 行。这是怎么回事?如果存在该子查询,为什么会涉及这么多行? Pets.Name 列肯定有唯一的数据(但据我所知没有唯一的约束)。

请注意,正如我所期望的那样,将谓词移至 WHERE 子句不会影响任何一种情况下的查询,因为它是 INNER JOIN。

见解赞赏!


根据我的经验,查询越复杂,SQL 优化器创建灵活计划的能力就越差。这里你有 16 个连接,一些或大部分是外部连接,你至少有一个子查询......扔进足够的索引,基数,视图,外部应用,谁知道还有什么,没有人,甚至微软都没有工程师*,可以找出统一、定期生成最佳计划的例程。

你所描述的,我已经经历过很多次了——在混乱的查询中改变一件简单的事情,一切都会快一个数量级(或者,咬牙切齿,慢一些)。我没有办法确定什么时候复杂就太复杂了,这更多的是一种感觉。我的一般经验法则是,如果它看起来太长或太复杂,请尽可能简化 - 例如您预先选择的单个嵌套值,或者打破查询的一部分always使用小结果集快速运行,首先运行它并将结果存储在临时表中。

(*请注意,这是轻微的讽刺)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么这个(不相关的)子查询会导致这样的问题? 的相关文章

随机推荐