Это побочный вопрос из порядка сортировки, указанного в первичном ключе, но сортировка выполняется в 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
ORDER BY
туда, тогда вы знаете, что можете положиться на это. Смотрите № 3 здесьORDER BY
предложение сильно ударило по производительности ( для получения дополнительной информации прочитайте другой вопрос ). У меня есть решение, которое работает на данный момент, но оно не будет работать, когда и если мой трафик увеличится.ORDER BY
условие в запросе. Это верно для SQL Server , Oracle , MySQL и любых других СУБД, о которых вы только можете подумать. Попробуйте что-нибудь еще, и вы готовитесь к неожиданной чашке неудач.Ответы:
Позвольте мне попытаться объяснить, почему вы не должны этого делать, почему вы никогда не должны предполагать, что продукт SQL будет возвращать набор результатов в определенном порядке, если вы не укажете это, независимо от того, какие индексы - кластеризованные или некластеризованные, B-деревья или R-деревья или kd-деревья или фрактальные деревья или любые другие экзотические индексы, используемые СУБД.
Ваш исходный запрос указывает СУБД на поиск в
SensorValues
таблице, поиск строк, соответствующих трем условиям, упорядочение этих строк поDate
убыванию, сохранение только первой строки из этих и, наконец, выбор и возврат толькоSensorValue
столбца.Это очень конкретные заказы, которые вы дали СУБД, и результат, скорее всего, будет одинаковым при каждом выполнении запроса (есть вероятность, что это не так, если у вас более одной строки, соответствующей условиям и имеющей одинаковые макс,
Date
но отличается,SensorValue
но давайте предположим, что до конца разговора таких строк в вашей таблице не существует).Должна ли СУБД делать это, чтобы выполнить этот запрос, точно так, как я это описал выше? Нет, конечно нет, и вы это знаете. Возможно, он не читает таблицу, но читает из индекса. Или он может использовать два индекса, если считает, что он лучше (быстрее). Или три. Либо он может использовать кэшированный результат (не SQL Server, а другие результаты запроса кеша СУБД). Или он может использовать параллельное выполнение один раз, а не при следующем запуске. Или ... (добавить любую другую функцию, которая влияет на выполнение и планы выполнения).
Однако гарантируется, что он будет возвращать один и тот же результат каждый раз, когда вы его запускаете - до тех пор, пока строки не будут вставлены, удалены или обновлены.
Теперь давайте посмотрим, что говорит ваше предложение:
Этот запрос предписывает СУБД выполнить поиск в
SensorValues
таблице, найти строки, соответствующие 3 условиям,упорядочить эти строки поне заботиться о порядке, оставить только одну строку и, наконец, выбрать и вернуть толькоDate
убыванию,SensorValue
столбец.Таким образом, он в основном говорит то же, что и первый, за исключением того, что он говорит, что вы хотите получить только один результат, который соответствует условиям, и вам все равно, какой именно .
Теперь мы можем предположить, что это даст всегда один и тот же результат из-за кластеризованного индекса?
- Если он использует этот кластерный индекс каждый раз, да.
Но будет ли это использовать?
- нет
Почему бы нет?
- Потому что это может. Оптимизатор запросов может свободно выбирать путь выполнения каждый раз, когда запускает оператор. Какой бы путь он не счел нужным в то время для этого заявления.
Но разве использование кластерного индекса не является лучшим / быстрым способом получения результатов?
Нет, не всегда. Это может быть первый раз, когда вы запускаете запрос. Во второй раз он может использовать кэшированный результат (если СУБД имеет такую функцию, а не SQL Server * ). В тысячный раз результат может быть удален из кэша, и там может существовать другой результат. Скажем, вы выполнили этот запрос незадолго до этого:
и кэшированный результат (из вышеприведенного запроса) является другим, отличающимся от него, который все еще соответствует вашим условиям, но не является первым в вашем (требуемом) порядке. И вы сказали СУБД не заботиться о заказе.
ОК, так что только кеш может повлиять на это?
- Нет, многое другое тоже.
*: SQL Server не кэширует результаты запроса, но Enterprise Edition имеет функцию расширенного сканирования, которая похожа на то, что вы можете получить разные результаты из-за одновременных запросов. Хотя точно не уверен, когда это произойдет. (спасибо @Martin Smith за совет.)
Я надеюсь, что вы убеждены, что никогда не следует полагаться на то, что SQL-запрос будет возвращать результаты в определенном порядке, если вы не укажете это. И никогда не используйте
TOP (n)
безORDER BY
, если, конечно, вы просто хотите n строк в результате, и вам все равно, какие из них будут возвращены.источник