在SQL Server数据库上,考虑如下所示的经典父子关系:
create table Parent(
p_id uniqueidentifier primary key,
p_col1 int,
p_col2 int
);
create table Child(
c_id uniqueidentifier primary key,
c_p uniqueidentifier foreign key references Parent(p_id)
);
declare @Id int
set @Id = 1
while @Id <= 10000
begin
insert into Parent(p_id, p_col1, p_col2) values (NEWID(), @Id, @Id);
set @Id=@Id+1;
end
insert into Child(c_id, c_p) select NEWID(), p_id from Parent;
insert into Child(c_id, c_p) select NEWID(), p_id from Parent;
insert into Child(c_id, c_p) select NEWID(), p_id from Parent;
;
现在我有这两个等效的查询,一个使用内部查询,另一个使用左联接:
内部查询:
select *
from Child c
inner join Parent p
on p.p_id=c.c_p
where p.p_col1=1 or p.p_col2=2;
左联接查询:
select *
from Child c
left join Parent p
on p.p_id=c.c_p
where p.p_col1=1 or p.p_col2=2;
我认为sql优化器足够聪明,可以为这两个查询找出相同的执行计划,但事实并非如此。 内部查询的计划是这样的:
如果我只有一种情况,则优化器可以很好地工作,选择相同的计划:
where p.p_col1=1
但是,如果我在另一个不同的列上添加“或”,则它不再选择最佳计划:
where p.p_col1=1 or p.p_col2=2;
我错过了什么吗?还是缺少优化器的优化器?
答案 0 :(得分:2)
很明显,它是优化程序。
如果您在WHERE
子句中有一个条件(并且“ condition”可能是与AND
关联的条件,但没有与OR
s关联的条件),那么优化器可以轻松达到峰值并说“是的,条件有第二个表中的行,没有NULL
值比较,所以这实际上是一个内部联接”。
当条件由OR
连接时,该逻辑将变得更加困难。我认为您已经观察到优化器不会在更复杂的条件下执行此操作。
答案 1 :(得分:0)
有时,如果您更改条件的顺序,则生成的计划会有所不同。优化器不会检查所有可能的实现方案(不幸的是)。这就是为什么有时您必须使用提示进行优化的原因。