0

查询 1) == 2) 是根据估计的查询计划和实际计划吗?(统计数据会影响这里的实际计划吗?)

声明 @cat int -- 来自 prc 的输入参数

...

1)

select * 
from A as a
  join B as b
    on b.id = a.id
    on b.cat = @cat
  join C as c
    on c.fid = b.fid
    on c.cat = @cat
  where a.cat = @cat

2)

select * 
from A as a
  join B as b
    on b.id = a.id
    on b.cat = a.cat
  join C as c
    on c.fid = b.fid
    on c.cat = b.cat
  where a.cat = @cat

在我看来,这些在逻辑上应该是等价的,并且无论表中的实际差异如何,执行计划都应该始终相同。并且在连接中添加更多条件,或者在哪里添加更多的表,或者添加更多的表来连接不应该改变这一点。

有没有这种情况不是真的?

4

1 回答 1

0

优化器可能会受到 a.cat、b.cat 或 c.cat 中是否存在可用索引以及该索引是否也包括相关的 id 或 fid 列的影响。将简单的 WHERE 子句谓词下推到表级操作可能足够聪明。它也可能受到表的统计信息的影响。(如果参数的值恰好在 C 中出现一次,则开始处理 C 可能比开始处理 A 更有效;或者从 B 开始可能更有效;或者仍然可能更有效从 A 开始。优化器在执行语句之前不知道参数的值,而不是在准备好时能够看到它,这可能会也可能无关紧要。)

因此,正如评论中已经暗示的那样,如果不了解您正在使用的系统的更多信息(包括模式等),就无法做出明确的声明。

好消息是结果内容应该是一样的——不能保证执行计划。


我注意到大多数 SQL 系统需要一个关键字 ON 用于每个连接:

select * 
from A as a
  join B as b
    on b.id = a.id
    AND b.cat = @cat
  join C as c
    on c.fid = b.fid
    AND c.cat = @cat
  where a.cat = @cat

赛瑞恩问道:

鉴于执行计划可能不同,哪种查询方式“更好”。哪里更好被定义为:

  1. 更有可能被优化以提供更好的计划(或者不太可能混淆 SQL 优化器)。
  2. 更符合 SQL 约定。

这在一定程度上取决于 DBMS 及其优化器;在这方面没有经验主义的替代品,但请记住,在某个时间点凭经验确定的内容在另一个时间点可能是错误的,因为:

  1. 数据集的大小发生了变化
  2. 数据集现在有不同的统计分布
  3. 优化器可能已更改
  4. 可能有不同的索引可用

有很多方法可以进行连接,它(仍然)依赖于可用的索引。我可能会写:

SELECT * 
  FROM A JOIN B ON b.id  = a.id  AND b.cat = a.cat
         JOIN C ON c.fid = b.fid AND c.cat = b.cat
 WHERE a.cat = @cat
   AND b.cat = @cat
   AND c.cat = @cat

这里的逻辑是,A(id, cat) 和 B(id, cat) 上,B(fid, cat) 和 C(fid, cat) 上可能都有索引,优化器因此可以充分利用那些索引。WHERE 子句包含两个冗余项,但让优化器知道需要什么,并明确告诉它可能无法自行推断出的内容。如果您对优化器的质量有信心(并检查了它生成的查询计划),那么您可以消除 WHERE 子句中三个条件中的两个。

如果将参数放在 ON 子句中,优化器可能无法像没有它那样充分利用索引 - 同样,您必须尝试找出优化器的行为方式。

最后,正如已经暗示的那样,表上的索引集至关重要,确保 DBMS 需要的任何统计信息都是最新的通常很重要。还要记住,如果表最初很小,优化器可能会选择与表变大时不同的查询计划——所以在合理的水平上进行测试。除非您的生产表只包含几十行,否则不要对只有几十行的表的查询进行性能测试。

于 2010-01-15T16:44:36.893 回答