Заказ на хранение против заказа на результат

8

Это побочный вопрос из порядка сортировки, указанного в первичном ключе, но сортировка выполняется в SELECT .

@Catcall говорит это на предмет порядка хранения (кластеризованный индекс) и порядка вывода

Многие люди считают, что кластерный индекс гарантирует порядок сортировки на выходе. Но это не то, что он делает; это гарантирует порядок хранения на диске. Смотрите, например, этот пост в блоге .

Я прочитал сообщение в блоге Хьюго Корнелиса и понял, что индекс не гарантирует, что сервер sql читает записи в определенном порядке. И все же мне трудно принять, что я не могу принять это за свой сценарий?

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

Мой оригинальный запрос был такой:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

Но я полагаю, что я мог бы также использовать этот (читай ниже для моего объяснения):

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

Как видите, строки моей таблицы маленькие (16 байт), и у меня есть только один индекс - кластеризованный. В моем сценарии на данный момент таблица состоит из 100 000 000 записей (и это, скорее всего, увеличится в десять раз).

Когда сервер базы данных запрашивает эту таблицу, у него есть два способа найти мои строки, либо он ищет первичный ключ и, таким образом, читает и возвращает мои значения в desc. порядок даты, или он должен сделать полное сканирование таблицы. Мой вывод заключается в том, что полное сканирование таблицы по всем этим записям будет слишком медленным, и поэтому сервер базы данных всегда будет искать таблицу по первичному ключу и, таким образом, возвращать значения, отсортированные поDate DESC

m__
источник
2
Почему вы хотите так сильно полагаться на это предположение? Почему бы вам просто не поставить ORDER BYтуда, тогда вы знаете, что можете положиться на это. Смотрите № 3 здесь
Аарон Бертран
По двум причинам: любопытство и потому, что это ORDER BYпредложение сильно ударило по производительности ( для получения дополнительной информации прочитайте другой вопрос ). У меня есть решение, которое работает на данный момент, но оно не будет работать, когда и если мой трафик увеличится.
m__
1
ORDER BY не должен быть ударом по производительности, если вы полагаетесь на порядок, который видите без заказа, - для меня это не имеет смысла.
Аарон Бертран
4
Единственное , что гарантирует результат установленный порядок является ORDER BYусловие в запросе. Это верно для SQL Server , Oracle , MySQL и любых других СУБД, о которых вы только можете подумать. Попробуйте что-нибудь еще, и вы готовитесь к неожиданной чашке неудач.
Ник Чаммас

Ответы:

15

Позвольте мне попытаться объяснить, почему вы не должны этого делать, почему вы никогда не должны предполагать, что продукт SQL будет возвращать набор результатов в определенном порядке, если вы не укажете это, независимо от того, какие индексы - кластеризованные или некластеризованные, B-деревья или R-деревья или kd-деревья или фрактальные деревья или любые другие экзотические индексы, используемые СУБД.


Ваш исходный запрос указывает СУБД на поиск в SensorValuesтаблице, поиск строк, соответствующих трем условиям, упорядочение этих строк по Dateубыванию, сохранение только первой строки из этих и, наконец, выбор и возврат только SensorValueстолбца.

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC ;

Это очень конкретные заказы, которые вы дали СУБД, и результат, скорее всего, будет одинаковым при каждом выполнении запроса (есть вероятность, что это не так, если у вас более одной строки, соответствующей условиям и имеющей одинаковые макс, Dateно отличается, SensorValueно давайте предположим, что до конца разговора таких строк в вашей таблице не существует).

Должна ли СУБД делать это, чтобы выполнить этот запрос, точно так, как я это описал выше? Нет, конечно нет, и вы это знаете. Возможно, он не читает таблицу, но читает из индекса. Или он может использовать два индекса, если считает, что он лучше (быстрее). Или три. Либо он может использовать кэшированный результат (не SQL Server, а другие результаты запроса кеша СУБД). Или он может использовать параллельное выполнение один раз, а не при следующем запуске. Или ... (добавить любую другую функцию, которая влияет на выполнение и планы выполнения).

Однако гарантируется, что он будет возвращать один и тот же результат каждый раз, когда вы его запускаете - до тех пор, пока строки не будут вставлены, удалены или обновлены.


Теперь давайте посмотрим, что говорит ваше предложение:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010 ;

Этот запрос предписывает СУБД выполнить поиск в SensorValuesтаблице, найти строки, соответствующие 3 условиям, упорядочить эти строки по Dateубыванию, не заботиться о порядке, оставить только одну строку и, наконец, выбрать и вернуть только SensorValueстолбец.

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

Теперь мы можем предположить, что это даст всегда один и тот же результат из-за кластеризованного индекса?
- Если он использует этот кластерный индекс каждый раз, да.

Но будет ли это использовать?
- нет

Почему бы нет?
- Потому что это может. Оптимизатор запросов может свободно выбирать путь выполнения каждый раз, когда запускает оператор. Какой бы путь он не счел нужным в то время для этого заявления.

Но разве использование кластерного индекса не является лучшим / быстрым способом получения результатов?
Нет, не всегда. Это может быть первый раз, когда вы запускаете запрос. Во второй раз он может использовать кэшированный результат (если СУБД имеет такую ​​функцию, а не SQL Server * ). В тысячный раз результат может быть удален из кэша, и там может существовать другой результат. Скажем, вы выполнили этот запрос незадолго до этого:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date ASC ;         --- Notice the `ASC` here

и кэшированный результат (из вышеприведенного запроса) является другим, отличающимся от него, который все еще соответствует вашим условиям, но не является первым в вашем (требуемом) порядке. И вы сказали СУБД не заботиться о заказе.

ОК, так что только кеш может повлиять на это?
- Нет, многое другое тоже.

  • другие индексы в то время рассматривались СУБД как более подходящие для этого запроса.
  • разработчик изменил или полностью удалил этот кластерный индекс, который у вас был.
  • Вы или какой-либо другой разработчик добавили другой индекс, который оптимизатор решил использовать более эффективно, чем CI.
  • Вы обновились до новой версии, и у нового оптимизатора есть небольшая ошибка или изменение в том, как он ранжирует и выбирает планы выполнения.
  • статистика была обновлена.
  • вместо этого было выбрано параллельное выполнение.

*: SQL Server не кэширует результаты запроса, но Enterprise Edition имеет функцию расширенного сканирования, которая похожа на то, что вы можете получить разные результаты из-за одновременных запросов. Хотя точно не уверен, когда это произойдет. (спасибо @Martin Smith за совет.)


Я надеюсь, что вы убеждены, что никогда не следует полагаться на то, что SQL-запрос будет возвращать результаты в определенном порядке, если вы не укажете это. И никогда не используйте TOP (n)без ORDER BY, если, конечно, вы просто хотите n строк в результате, и вам все равно, какие из них будут возвращены.

ypercubeᵀᴹ
источник
2
SQL Server Enterprise Edition имеет расширенную функцию сканирования, которая похожа на то, что вы можете получить разные результаты из-за одновременных запросов. Хотя точно не уверен, когда это произойдет.
Мартин Смит
1
Другая вещь, которая потенциально «рандомизирует» порядок результирующих наборов (даже если запрос, очевидно, управляется упорядоченным индексом), это параллелизм. Я видел, что приложение, которое успешно работало с неработающим SQL, начало работать плохо после включения автоматического параллелизма (не SQL Server, но я думаю, что это также может быть применимо и там).
Мат