Парадокс производительности запроса: уникальный кластерный и неуникальный некластеризованный индекс

У меня есть таблица MY_TABLE примерно с 9 миллионами строк.

В этой таблице всего 38 столбцов. Столбцы, которые имеют отношение к моему вопросу:

  • RECORD_ID: идентификатор, bigint, с уникальным кластеризованным индексом
  • RECORD_CREATED: datetime, с неуникальным и некластеризованным индексом

Теперь я запускаю следующие два запроса и, естественно, ожидаю, что первый будет выполняться быстрее, потому что данные сортируются по столбцу с уникальным кластеризованным индексом, но каким-то образом он выполняется в 271 раз (!) Медленнее.

SELECT TOP 1 
    RECORD_ID 
FROM 
    MY_TABLE 
WHERE 
    RECORD_CREATED >= '20140801' 
ORDER BY 
    RECORD_ID

SELECT TOP 1 
    RECORD_ID 
FROM 
    MY_TABLE 
WHERE 
    RECORD_CREATED >= '20140801' 
ORDER BY 
    RECORD_CREATED

Время выполнения составляет 1630 мс и 6 мс соответственно.

Пожалуйста, порекомендуйте.

P.S.: Из-за политики безопасности среды я не могу видеть план выполнения или использовать SQL Profiler.


person anar khalilov    schedule 10.09.2014    source источник
comment
Второй - это просто прямой поиск по индексу. Прочтите первую строку больше или равную точке поиска и возможный однократный поиск, если индекс не покрывает. И в вашем случае индекс будет покрывать, поскольку NCI всегда включает ключ CI, поэтому поиск не требуется.   -  person Martin Smith    schedule 10.09.2014
comment
@MartinSmith, мне очень жаль, но я не полностью понял ваш комментарий. Не могли бы вы объяснить немного подробнее? Ответ тоже приветствуется.   -  person anar khalilov    schedule 10.09.2014
comment
Я не буду утруждать себя ответом, потому что у меня нет ПК. В общем RECORD_CREATED >= '20140801 может быть удовлетворен поиском диапазона. Нахождение соответствующей точки в указателе и последующее его сканирование. Поскольку вам просто нужна первая 1 в порядке индекса, SQL Server может остановить поиск диапазона, как только он прочитает первую строку. Ваш список выбора фактически находится в другом столбце record_id, но он также автоматически включается в некластеризованный индекс, поскольку он является ключом кластеризованного индекса.   -  person Martin Smith    schedule 10.09.2014


Ответы (1)


У SQL Server есть несколько вариантов выполнения этого запроса. Он может начать с сортировки всех элементов, используя указанные вами индексы, а затем отфильтровать любые элементы, которые не соответствуют предложению WHERE. Однако обычно быстрее сократить размер набора данных, с которым вы работаете в первую очередь, поэтому вам не нужно сортировать такое количество элементов.

Таким образом, SQL Server, скорее всего, сначала выберет фильтр WHERE. Когда он это делает, он, скорее всего, начинает с использования неуникального некластеризованного индекса для RECORD_CREATED, чтобы пропустить все элементы, где RECORD_CREATED меньше, чем '20140801', а затем взять все элементы после этого.

На этом этапе все элементы предварительно отсортированы в том порядке, в котором они были найдены в индексе RECORD_CREATED, поэтому второй запрос не требует дополнительных усилий, но первый запрос затем должен выполнить сортировку выбранных записей. .

person StriplingWarrior    schedule 10.09.2014
comment
Что, если бы двигатель решил сначала выполнить сортировку? Был бы другой вариант быстрее? Думаю, что нет, все же второй вариант был бы быстрее, не так ли? - person anar khalilov; 10.09.2014
comment
Я не волшебник, когда дело доходит до оптимизации БД, но я предполагаю, что это зависит от нескольких факторов, например, сколько элементов в таблице соответствует предложению WHERE. - person StriplingWarrior; 10.09.2014