Как SQL Server сортирует ваши данные?

Мне было интересно, как SQL Server сортирует данные. Я заметил, что если у меня есть таблица, в которой не содержится столбец "Идентификатор", и вы выбираете данные без "ORDER BY", сервер sql автоматически не сортирует первичный столбец.

Кто-нибудь знает, что следует за сервером SQL Server для сортировки данных?

Ответ 1

Хотя интересно спросить, как можно объяснить, что вы часто видите тот же порядок, я хотел бы указать, что никогда не стоит полагаться на неявный порядок, вызванный конкретной реализацией базового механизма базы данных, Другими словами, приятно знать, почему, но вы никогда не должны полагаться на это. Для MS SQL единственное, что надежно доставляет строки в определенном порядке, - это явное предложение ORDER BY.

Не только разные RDMBS-es ведут себя по-разному, один конкретный экземпляр может вести себя по-разному из-за обновления (patch). Мало того, что даже состояние программного обеспечения РСУБД может оказать влияние: "теплая" база данных ведет себя иначе, чем "холодная", небольшая таблица ведет себя не так, как большая.

Даже если у вас есть справочная информация о реализации (например: "есть кластеризованный индекс, поэтому, скорее всего, данные будут возвращены по порядку кластерного индекса" ), всегда существует вероятность того, что существует еще один механизм вы не знаете об этом, заставляя строки возвращаться в другом порядке (ex1: ", если другой сеанс просто выполнил полное сканирование таблицы с явным ORDER BY, возможно, что набор результатов был кэширован, последующее полное сканирование будет пытаться вернуть строки из кеша"; ex2: "a GROUP BY может быть реализовано путем сортировки данных, что влияет на порядок возврата строк"; ex3: "Если выбранные столбцы имеют вторичный индекс, который уже кэширован в памяти двигатель может сканировать вторичный индекс вместо таблицы, скорее всего, возвращая строки по порядку вторичного индекса" ).

Вот очень простой тест, который иллюстрирует некоторые из моих моментов.

Во-первых, запуск SQL-сервера (я использую 2008). Создайте эту таблицу:

create table test_order (
    id int not null identity(1,1) primary key
,   name varchar(10) not null 
)

Изучите таблицу и убедитесь, что создан скопированный индекс для поддержки primary key в столбце id. Например, в студии управления сервером sql вы можете использовать древовидное представление и перейти к папке индексов под вашей таблицей. Там вы должны увидеть один индекс с именем типа: PK__test_ord__3213E83F03317E3D (Clustered)

Вставьте первую строку с этим выражением:

insert into test_order(name)
select RAND()

Вставьте больше строк, повторяя эту инструкцию 16 раз:

insert into test_order(name)
select RAND()
from   test_order

Теперь вы должны иметь 65536 строк:

select COUNT(*) 
from   test_order

Теперь выберите все строки без использования порядка:

select *
from   test_order

Скорее всего, результаты будут возвращены по порядку первичного ключа (хотя гарантии нет). Вот результат, который я получил (который действительно по порядку первичного ключа):

#      id    name
1      1     0.605831
2      2     0.517251
3      3     0.52326
.      .     .......
65536  65536 0.902214

(# не является столбцом, а порядковым положением строки в результате)

Теперь создайте вторичный индекс в столбце name:

create index idx_name on test_order(name)

Выберите все строки, но получите только столбец name:

select name
from   test_order

Скорее всего, результаты будут возвращены по порядку вторичного индекса idx_name, так как запрос может быть разрешен только путем сканирования индекса (i.o.w. idx_name является индексом покрытия). Вот результат, который я получил, который действительно по порядку name.

#      name
1      0.0185732
2      0.0185732
.      .........
65536  0.981894

Теперь снова выберите все столбцы и все строки:

select * 
from test_order

Вот результат, который я получил:

#      id    name
1      17    0.0185732
2      18    0.0185732
3      19    0.0185732
...    ..    .........

как вы можете видеть, совсем не так, как в первый раз мы выполнили этот запрос. (Похоже, что строки упорядочены по второстепенному индексу, но у меня нет объяснений, почему это должно быть так).

В любом случае, нижняя строка - не полагаться на неявный порядок. Вы можете придумать объяснения, почему можно наблюдать определенный порядок, но даже тогда вы не можете всегда его предсказать (как в последнем случае), не имея интимного знания о состоянии реализации и времени выполнения.

Ответ 2

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

Вы можете увидеть пример этого в в этой статье.

Ответ 3

AS SQL основан на Set thoery, и Set не гарантирует никакого заказа, поэтому, если вы не укажете конкретный порядок явно, заказ не будет гарантирован.

Ответ 4

У меня был похожий опыт работы с результатами SQL Server, отсортированными по-разному, чем я ожидал. Я обнаружил, что если вы укажете подсказку таблицы в инструкции select, указав имя кластерного индекса, вы получите упорядоченные результаты, как вы хотите:

select * from test_order WITH (INDEX([ClusteredIndexName]))