Подсказка NOLOCK меняет порядок возвращаемых записей

11

Кластерный индекс в Clientполе таблицы LastName.

Когда я просто выкидываю все записи из таблицы, они отображаются в алфавитном порядке, если только (nolock)подсказка не используется в рассматриваемом запросе. Этот намек меняет порядок записей. Должно ли это? Я уверен, что ни у одной другой сессии нет открытой транзакции с изменениями в этой таблице (по крайней мере sp_who2, не показывает мне ничего).

Как объяснить разницу в заказе?

Дополнительная информация, извлеченная из комментариев:

  1. Там нет заказа по. Должен ли некластерный индекс обеспечивать порядок?

  2. Запросы по-прежнему возвращают другой порядок, даже если используется указатель индекса, указывающий кластеризованный индекс. Должны ли они? Мне интересно, почему nolockменяется порядок возвращаемых записей без видимого изменения планов.

  3. Я сделал WinDiff для них - то же самое за исключением [the] (nolock)[подсказка запроса].

ajeh
источник
21
Подсказка не меняет порядок - потому что нет порядка, который можно изменить
a_horse_with_no_name

Ответы:

47

Появление упорядоченного результирующего набора без ORDER BYпредложения часто является результатом сканирования, извлекающего строки в порядке индекса. Одна из причин, по которой сканирование в порядке индекса обычно выбирается в соответствии с READ COMMITTEDуровнем изоляции по умолчанию, заключается в том, что оно уменьшает вероятность нежелательных аномалий параллелизма, таких как многократное обнаружение одной и той же строки или полный пропуск некоторых строк. Это подробно описано в нескольких местах, в том числе в этой серии статей об уровнях изоляции.

С NOLOCKтабличной подсказкой это поведение смягчается, и доступ к таблице осуществляется при более терпимом READ UNCOMMITTEDуровне изоляции, который может сканировать данные в порядке размещения вместо порядка индекса. Как описано в этой ссылке, решение о том, использовать ли сканирование порядка распределения или индекса, остается за механизмом хранения. Этот выбор может меняться между выполнениями без изменения в плане запроса .

Это может звучать очень абстрактно, но может быть легче продемонстрировано с некоторыми запросами, использующими недокументированные функции к базе данных AdventureWorks2012 .

USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
    P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;

-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);

Результаты запроса

Запросы заимствованы с небольшой модификацией от Пола Уайта .

Наконец, просто чтобы прояснить, этот ответ о появлении упорядоченного набора результатов. Там нет гарантированного заказа презентации без верхнего уровня ORDER BY.

Сканирование порядка размещения может происходить при множестве других обстоятельств, например, когда получена блокировка на уровне таблицы или база данных находится в режиме только для чтения. Параллелизм также может влиять на порядок, в котором возвращаются данные. Ключевым моментом является то ORDER BY, что без этого данные, в которых возвращаются данные, могут изменяться с течением времени в зависимости от конструкции.

Джеймс Л
источник
7
Хороший, намного более конкретный, чем моя недооцененная попытка. Суть в ваших последних двух параграфах, конечно. «Почему» в действительности не имеет значения. Может быть, вам повезет больше ударить этот аккорд, чем я.
Аарон Бертран
12

Когда я просто сбрасываю все записи из таблицы

... тогда вы не должны ожидать какого-либо заказа. Фактически, один и тот же запрос, выполняемый несколько раз, может возвращаться в другом порядке без предупреждения. Причина в том, что два ваших запроса - которые являются «разными» запросами, скорее всего, из-за разного текста запроса, а не из-за подсказки), имеют разные планы выполнения (и разница может быть незначительной, например, итератор, который выглядит одинаково в оба плана, но ordered: trueтолько в одной или очень различном количестве оценочных строк, потому что один был скомпилирован до существенного изменения данных). Возможно также, что выполняется сканирование порядка распределения, как правильно заметил Джеймс в своем ответе.

В любом случае, поскольку вы выполняете запрос без ORDER BY, SQL Server делает вывод, что вам не нужен порядок, и поэтому отключается и определяет наиболее эффективный способ возврата строк (его не волнует порядок, если вы этого не делаете. ).

Позвольте мне сделать это очень ясно:

Если вы хотите или ожидаете определенный заказ, добавьте предложение ORDER BY

Это дошло до:

И я написал об этом в блоге:

Вот цитата из последнего, которая повторяет то, что я сказал в ответ на ваш комментарий об использовании подсказки индекса вместо ORDER BYпредложения:

Даже в случае хинтованного индекса будет использоваться индекс (если это возможно, в противном случае в большинстве случаев будет ошибка), но только потому, что индекс используется, не означает, что результаты будут возвращены отсортированными по ключу (ключам) в этот индекс. Вам все еще нужно ORDER BYобеспечить сортировку по ключу (ключам) индекса.

Конор Каннингем - довольно умный парень, непосредственно ответственный за большую часть того, что делает SQL Server, когда обрабатывает запрос для вас - также написал об этом здесь:

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

Аарон Бертран
источник
11

Джеймс прекрасно объяснил, как это работает, но я хотел бы еще раз повторить одну вещь: если вы не используете функцию упорядочения, порядок строк в наборе результатов не определен . Если вам нужен определенный порядок, используйте явное order byпредложение - если вы его не укажете, вы в основном говорите: «Меня не волнует порядок», а не «Упорядочить по кластерному индексу».

Luaan
источник