У меня есть два индексированных представления, v_First
и v_Second
. Эти представления отлично работают, когда у меня есть предложение WHERE
, которое фильтрует только на основе одного из этих представлений, однако, как только у меня есть критерии фильтрации на основе обоих представлений, я получаю два сканирования кластерного индекса и в результате низкую производительность.
Мой запрос:
SELECT * FROM dbo.v_First (NOEXPAND)
JOIN dbo.v_Second (NOEXPAND)
ON dbo.v_First.id = dbo.v_Second.id
WHERE
dbo.v_First.Firstname = 'JUSTIN'
OR dbo.v_Second.Surname = 'JUSTIN'
Если я закомментирую одно из двух вышеупомянутых предложений WHERE
, я получаю поиск и запрос выполняется, поэтому я знаю, что индивидуально у меня определены правильные индексы.
Почему запрос не выполняется при фильтрации на основе нескольких проиндексированных представлений и что я могу сделать, чтобы это исправить?
(Извините, я не могу публиковать планы выполнения, они все равно тривиальны - всего два сканирования кластерного индекса для двух соответствующих представлений, кластеризованный индекс и соединение слиянием)
Обновление:
Столбцы v_First:
- ID (bigint, кластерный индекс)
- FirstName (varchar (254), некластеризованный индекс)
Столбцы v_Second:
- ID (bigint, кластерный индекс)
- Фамилия (varchar (254), некластеризованный индекс)
Все индексы содержат только один столбец.
Обновление, второе:
Я обнаружил, что если предложение OR
заменяется предложением AND
, запрос выполняется нормально. Я также обнаружил, что если я изменю запрос на использование оператора UNION
вместо OR
, запрос будет выполняться нормально:
SELECT * FROM dbo.v_First (NOEXPAND)
JOIN dbo.v_Second (NOEXPAND)
ON dbo.v_First.ID = dbo.v_Second.ID
WHERE dbo.v_First.Firstname = 'JUSTIN'
UNION SELECT * FROM dbo.v_First (NOEXPAND)
JOIN dbo.v_Second (NOEXPAND)
ON dbo.v_First.ID = dbo.v_Second.ID
WHERE dbo.v_Second.Surname = 'JUSTIN'
Насколько мне известно, эти два запроса должны быть эквивалентны?
Наконец, я также обнаружил, что использование подзапроса вместо этого также имеет странный эффект, следующий запрос работает нормально:
SELECT * FROM dbo.v_First (NOEXPAND)
-- JOIN dbo.v_Second (NOEXPAND)
-- ON dbo.v_First.ID = dbo.v_Second.ID
WHERE dbo.v_First.ID IN
(
SELECT ID FROM dbo.v_Second (NOEXPAND)
WHERE dbo.v_Second.Surname = 'JUSTIN'
)
OR dbo.v_First.Firstname = 'JUSTIN'
Однако, если я раскомментирую JOIN
(чтобы я мог получить столбцы из второй таблицы в результатах моего запроса), я получу сканирование таблицы по кластерному индексу v_Second (обратите внимание, что это все же лучше, чем исходный запрос, поскольку он включает только 1 скан вместо 2).
Я очень запутался - что происходит? Кажется, что я могу обойти эти проблемы, «рефакторируя» свой запрос, однако меня беспокоит, что я не понимаю, что здесь происходит - я бы предпочел избегать внесения изменений, которые я не полностью понимаю.