Почему SQL-сервер не использует мой индекс? (Фильтрация по объединенным индексированным представлениям)

У меня есть два индексированных представления, 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).

Я очень запутался - что происходит? Кажется, что я могу обойти эти проблемы, «рефакторируя» свой запрос, однако меня беспокоит, что я не понимаю, что здесь происходит - я бы предпочел избегать внесения изменений, которые я не полностью понимаю.


person Justin    schedule 10.08.2010    source источник
comment
@OMG - Практически только столбцы и индексы, которые абсолютно необходимы для создания индексированного представления - я обновил свой вопрос.   -  person Justin    schedule 10.08.2010
comment
Даже с таблицей только с идентификатором, именем, фамилией, сгруппированной по идентификатору и проиндексированной по имени и фамилии отдельно, самосоединение по строкам вашего запроса приводит к такому же «плохому» плану запроса + медленному выполнению. Введение второй таблицы с той же схемой, что и первая, и с такими же индексами не улучшает запрос. Интересный.   -  person Will A    schedule 10.08.2010
comment
Один вопрос: откуда в базовой таблице могут быть строки?   -  person gbn    schedule 10.08.2010
comment
@gbn - В базовой таблице ~ 3 000 000 строк, однако они отфильтрованы примерно до 1 000 000 в каждом из представлений. Однако это всего лишь выборка данных для исследования возможных проблем с производительностью - реальный набор данных, скорее всего, будет превышать 12 миллионов записей в базовой таблице.   -  person Justin    schedule 10.08.2010


Ответы (1)


Наблюдения

  • У вас есть условие «ИЛИ», которое не подлежит поиску

  • Возможно, вам потребуется добавить идентификатор к каждому индексу, чтобы он был доступен без сканирования / поиска.

  • Я все равно хотел бы увидеть планы. Используйте SET SHOWPLAN_TEXT.

Чтобы ответить на ваш вопрос, я бы, вероятно, имел один индекс в базовой таблице с обоими текстовыми столбцами и позволил бы ему сканировать его. ИЛИ не дает вам много вариантов, а 2 индексированных просмотра бессмысленны, ИМХО. После обновления у вас есть несколько надуманных конструкций SQL: действительно ли вам нужны 2 индексированных представления и причудливая производная таблица или UNION?

person gbn    schedule 10.08.2010
comment
Индексированные представления призваны обойти некоторые ограничения базовых таблиц - это очень странно и далеко не идеально - я исследую индексированные представления как подход меньшего из двух зол. - person Justin; 10.08.2010