这两个sql查询在所有方面是否相同(例如估计和实际执行计划)?

时间:2010-01-15 16:35:03

标签: sql sql-execution-plan

查询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

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

是否存在这种情况?

1 个答案:

答案 0 :(得分: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

Xerion问:

  

鉴于执行计划可能不同,查询的方式是“更好”。其中更好的定义为:

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

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

  1. 数据集的大小已更改
  2. 现在数据集具有不同的统计分布
  3. 优化程序可能已更改
  4. 可能有不同的索引
  5. 有许多方法可以进行连接,它确实(仍然)依赖于可用的索引。我可能会写:

    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所需的任何统计信息都是最新的通常很重要。还要记住,如果表最初很小,优化器可能会从表变大的时候选择不同的查询计划 - 所以在合理的级别进行测试。除非生产表只包含几十行,否则不要对只有几十行的表进行查询性能测试。