Sql Server выполняет полное сканирование таблицы, когда первое поле в PK имеет несколько различных значений

У меня есть эта таблица (Таблица A):

(
    [FieldA] [int] NOT NULL,
    [FieldB] [int] NOT NULL,
    [Value] [float] NULL
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED 
(
    [FieldA] ASC,
    [FieldB] ASC
)

Существует несколько различных значений FieldA, скажем, FieldA может быть {1,2,3,4,5,6}.

Почему этот запрос вызывает полное сканирование таблицы:

SELECT COUNT(*) FROM TableA WHERE FieldB = 1

Пока это не так:

SELECT COUNT(*) FROM TableA WHERE FieldB = 1 where FieldA in (1,2,3,4,5,6)

Сервер Sql не может оптимизировать это? Если бы у меня был TableB, где FieldA был PK, и я присоединился к TableB и TableA, запрос выполнялся бы аналогично второму запросу.

2 ответа

Решение

Очевидно, что я искал оптимизацию с пропуском сканирования, которая доступна в Oracle, но не в SQL Server. Пропуск сканирования может использовать индекс, если отсутствует предикат переднего края столбца: http://social.msdn.microsoft.com/Forums/eu/transactsql/thread/48de15ad-f8e9-4930-9f40-ca74946bc401

Созданный вами кластерный индекс основан на двух столбцах. Если вы выполняете поиск только по одному из этих столбцов, SQL Server не может сгенерировать "ключевое" значение для использования в процессе поиска по этому индексу, поэтому он прибегает к подходу сканирования таблиц.

Хотя FieldA имеет очень маленький диапазон значений, которые он может содержать, оптимизатор SQL не смотрит на этот диапазон значений, чтобы определить, может ли он "выдумать" ключ из информации, которую вы ему дали.

Если вы хотите повысить производительность первого запроса, вам нужно будет создать еще один индекс для FieldB. Если, как вы говорите, в FieldA не так много различных значений, и вы выполняете большинство ваших поисков исключительно на FieldB, вы можете рассмотреть возможность перемещения кластерного индекса, который будет построен только на FieldB, и создания уникального индекса для FieldA и FieldB.

Другие вопросы по тегам