A union
удаляет дубликаты, и SQL Server, к сожалению, может не обнаружить, что такое удаление не требуется, когда результат union
используется в предикате IN
.
SELECT name
FROM products
WHERE id IN (
SELECT product_id
FROM orders
UNION ALL
SELECT 1);
UNION ALL
говорит, что дубликаты разрешены, поэтому это позволит избежать дорогостоящего этапа удаления дубликатов.Даже если вы можете подумать, что, поскольку вторая часть объединения имеет только одно значение, проверка дубликатов должна быть быстрой, это не так.UNION
говорит, что все дубликаты должны быть удалены.Он также должен удалить все повторяющиеся идентификаторы product_ids из первой части запроса.
Я только что провел несколько быстрых тестов и обнаружил одно повторение, в котором оптимизатор недостаточно умен, чтобы избежатьудаление дубликатов, для версий 2000, 2005, 2008. Все 3 показывают план запроса, который показывает отдельный вид сортировки, используемый после объединения между сканированием таблицы (из #IDs
) и постоянным сканированием:
create table #IDs (
ID int not null
)
go
insert into #IDs (ID)
select 1 union all
select 1 union all
select 2 union all
select 2 union all
select 3
go
select * from sysobjects where id in (select ID from #IDs union select 1)
go