查询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
在我看来,这些在逻辑上应该是等价的,并且无论表中的实际差异如何,执行计划都应始终相同。并且在连接中添加更多条件,或者在其中添加或添加更多要加入的表不应更改此条件。
是否存在这种情况?
答案 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问:
鉴于执行计划可能不同,查询的方式是“更好”。其中更好的定义为:
- 更有可能进行优化以提供更好的计划(或不太可能混淆SQL优化器)。
- 更符合SQL约定。
醇>
它取决于DBMS及其优化器;这方面的经验主义是无可替代的,但请记住,在某个时间点根据经验确定的内容在另一个时间点可能是错误的,因为:
有许多方法可以进行连接,它确实(仍然)依赖于可用的索引。我可能会写:
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所需的任何统计信息都是最新的通常很重要。还要记住,如果表最初很小,优化器可能会从表变大的时候选择不同的查询计划 - 所以在合理的级别进行测试。除非生产表只包含几十行,否则不要对只有几十行的表进行查询性能测试。