В базе данных 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;
Я что-то упустил или это оптимизатор пропускает это улучшение?