Я использую Microsoft SQL Server 2008 (SP1, x64). У меня есть два запроса, которые делают то же самое, или я так думаю, но у них совершенно разные планы запросов и производительность.
Запрос 1:
SELECT c_pk
FROM table_c
WHERE c_b_id IN (SELECT b_id FROM table_b WHERE b_z = 1)
OR c_a_id IN (SELECT a_id FROM table_a WHERE a_z = 1)
Запрос 2:
SELECT c_pk
FROM table_c
LEFT JOIN (SELECT b_id FROM table_b WHERE b_z = 1) AS b ON c_b_id = b_id
LEFT JOIN (SELECT a_id FROM table_a WHERE a_z = 1) AS a ON c_a_id = a_id
WHERE b_id IS NOT NULL
OR a_id IS NOT NULL
Запрос 1 быстрый, как я и ожидал, тогда как запрос 2 очень медленный. планы запросов выглядят совершенно иначе.
Я бы хотел, чтобы запрос 2 выполнялся так же быстро, как и запрос 1. У меня есть программное обеспечение, использующее запрос 2, и я не могу изменить его на запрос 1. Я могу изменить базу данных.
Некоторые вопросы:
- почему планы запросов отличаются?
- можно ли как-нибудь "научить" SQL Server, что запрос 2 равен запросу 1?
Все таблицы имеют (кластеризованные) первичные ключи и правильные индексы для всех столбцов:
CREATE TABLE table_a (
a_pk int NOT NULL PRIMARY KEY,
a_id int NOT NULL UNIQUE,
a_z int
)
GO
CREATE INDEX IX_table_a_z ON table_a (a_z)
GO
CREATE TABLE table_b (
b_pk int NOT NULL PRIMARY KEY,
b_id int NOT NULL UNIQUE,
b_z int
)
GO
CREATE INDEX IX_table_b_z ON table_b (b_z)
GO
CREATE TABLE table_c (
c_pk int NOT NULL PRIMARY KEY,
c_a_id int,
c_b_id int
)
GO
CREATE INDEX IX_table_c_a_id ON table_c (c_a_id)
GO
CREATE INDEX IX_table_c_b_id ON table_c (c_b_id)
GO
Таблицы не изменяются после заполнения изначально. Я единственный, кто их опрашивает. Они содержат миллионы записей (table_a: 5M, table_b: 4M, table_c: 12M), но использование только 1% дает аналогичные результаты.
Редактировать: я пытался добавить ИНОСТРАННЫЕ КЛЮЧИ для c_a_id
и c_b_id
, но это только замедляло запрос 1 ...
Я надеюсь, что кто-то может взглянуть на планы запросов и объяснить разницу.