SQL Server 2008: упорядочение по дате и времени слишком медленное - PullRequest
21 голосов
/ 11 ноября 2009

Моя таблица (SQL Server 2008) содержит более 1 миллиона записей, когда я пытаюсь упорядочить записи по дате и времени, это занимает 1 секунду, но когда я упорядочиваю по ID (int), это занимает всего около 0,1 секунды.

Есть ли способ повысить эффективность? (Я уже добавил столбец даты и времени в индекс)

Ответы [ 7 ]

25 голосов
/ 11 ноября 2009

Упорядочение по id, вероятно, использует сканирование кластерного индекса, тогда как при упорядочении по datetime используется либо сортировка, либо поиск по индексу.

Оба эти метода работают медленнее, чем сканирование кластерного индекса.

Если ваша таблица сгруппирована по id, это означает, что она уже отсортирована. Записи содержатся в B+Tree, который имеет связанный список, связывающий страницы в порядке id. Движок должен просто пройти по связанному списку, чтобы получить записи, упорядоченные по id.

Если id были вставлены в последовательном порядке, это означает, что физический порядок строк будет соответствовать логическому порядку, и сканирование кластеризованного индекса будет еще быстрее.

Если вы хотите, чтобы ваши записи были заказаны по datetime, есть два варианта:

  • Взять все записи из таблицы и отсортировать их. Медлительность очевидна.
  • Используйте индекс на datetime. Индекс хранится в отдельном пространстве диска, это означает, что движок должен переключаться между страницами индекса и страницами таблицы во вложенном цикле. Это тоже медленнее.

Чтобы улучшить порядок, вы можете создать отдельный индекс покрытия для datetime:

CREATE INDEX ix_mytable_datetime ON mytable (datetime) INCLUDE (field1, field2, …)

и включите в этот индекс все столбцы, которые вы используете в своем запросе.

Этот индекс похож на теневую копию вашей таблицы, но данные отсортированы в другом порядке.

Это позволит избавиться от поиска по ключевым словам (поскольку индекс содержит все данные), что позволит упорядочить на datetime так же быстро, как и на id.

Обновление:

Свежий пост в блоге по этой проблеме:

6 голосов
/ 11 ноября 2009

В честь заказа на двигатель есть две альтернативы:

  • сканировать строки, используя индекс, который предлагает запрошенный порядок
  • сортировка строк

Первый вариант быстрый, второй медленный. Проблема в том, что для использования индекс должен быть , охватывающим индекс . Это означает, что он содержит все столбцы в списке проекции SELECT и все столбцы, используемые в предложениях WHERE (как минимум). Если индекс не покрывает, то движок должен будет искать кластеризованный индекс (то есть «таблицу») для каждой строки, чтобы получить значения необходимых столбцов. Этот постоянный поиск значений дорог, и есть переломный момент, когда механизм (по праву) решит, что более эффективно просто сканировать кластеризованный индекс и сортировать результат, фактически игнорируя ваш некластеризованный индекс. Подробнее см. Ответы на критические вопросы .

Рассмотрим следующие три запроса:

SELECT dateColumn FROM table ORDER BY dateColumn
SELECT * FROM table ORDER BY dateColumn
SELECT someColumn FROM table ORDER BY dateColumn

Первый будет использовать некластеризованный индекс для dateColumn. Но второй не будет использовать индекс для dateColumn, скорее всего, выберет сканирование и сортировку вместо 1M строк. С другой стороны, третий запрос может выиграть от индекса на Table(dateColumn) INCLUDE (someColumn).

Эта тема в общем освещена в MSDN, см. Основы разработки индекса , Общие рекомендации по разработке индекса , Рекомендации по созданию некластерного индекса или Как: Оптимизировать индексы SQL .

В конечном счете, наиболее важным выбором вашей схемы таблиц является используемый вами кластерный индекс. Почти всегда первичный ключ (обычно с автоматически увеличивающимся идентификатором) остается в качестве кластеризованного индекса, решение, которое приносит пользу только определенным нагрузкам OLTP.

И, наконец, довольно очевидный вопрос: почему в мире вы бы заказали 1 миллион строк ?? Вы не можете отображать их, не так ли? Более подробное объяснение вашего варианта использования может помочь нам найти лучший ответ для вас.

2 голосов
/ 11 ноября 2009

Добавьте время даты к новому индексу, добавление его к идентификатору все равно мало поможет.

1 голос
/ 11 ноября 2009

Может ли быть так, что существует индекс для вашего столбца int, но не для столбца datetime? Посмотрите на план выполнения.

0 голосов
/ 11 ноября 2009

Вы добавили поле DateTime к индексу "to" или к эксклюзивному индексу? Вы фильтруете свой выбор по другому полю и DateTime или только этому?

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

0 голосов
/ 11 ноября 2009

Если ваше поле даты и времени содержит много различных значений, и эти значения редко изменяются, определите кластеризованный индекс в поле даты и времени, это позволит отсортировать фактические данные по значению даты и времени. См. http://msdn.microsoft.com/en-us/library/aa933131(SQL.80).aspx для использования кластерных индексов.

Однако это замедлит поиск в int, поскольку они будут использовать некластеризованный индекс.

0 голосов
/ 11 ноября 2009

возможно, если вы храните datatime как целое число, но при каждом сохранении или получении данных потребуется преобразование времени. (распространенный метод хранения персонала, такой как IP-адрес и более быстрое время поиска)

Вы должны проверить на своем сервере, как он хранит дату и время, потому что ваш сервер уже хранит его как int или bigint .. это ничего не изменит ....

...