Поскольку другие ответы уже указывают, что SQL Server может или не может явно гарантировать, что строки отсортированы в порядке кластеризованного индекса до insert
.
Это зависит от того, имеет ли оператор кластерного индекса в плане DMLRequestSort
набор свойств (который, в свою очередь, зависит от предполагаемого количества вставляемых строк).
Если вы обнаружите, что SQL Server недооценивает это по какой-либо причине, вам может быть полезно добавить явное выражение ORDER BY
в SELECT
запрос, чтобы минимизировать разбиение страниц и последующую фрагментацию в результате INSERT
операции.
Пример:
use tempdb;
GO
CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))
CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))
GO
DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)
INSERT INTO @T(N)
SELECT number
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499
/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
/*Same operation using explicit sort*/
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;
Показывает, что T
это сильно фрагментировано
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536 92535 92535 67.1668272794663 250000
99.5 200 200 74.2868173956017 92535
0 1 1 32.0978502594514 200
Но для T2
фрагментации минимально
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376 262 62500 99.456387447492 250000
2.1551724137931 232 232 43.2438349394613 62500
0 1 1 37.2374598468001 232
И наоборот, иногда вам может понадобиться заставить SQL Server недооценивать количество строк, если вы знаете, что данные уже предварительно отсортированы и хотите избежать ненужной сортировки. Один примечательный пример - вставка большого количества строк в таблицу с newsequentialid
ключом кластеризованного индекса. В версиях SQL Server до Denali SQL Server добавляет ненужные и потенциально дорогие операции сортировки . Этого можно избежать
DECLARE @var INT =2147483647
INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar
Затем SQL Server оценит, что будет вставлено 100 строк независимо от размера, Bar
который ниже порогового значения, при котором сортировка добавляется в план. Однако, как указано в комментариях ниже, это означает, что вставка, к сожалению, не сможет использовать минимальное ведение журнала.
Если оптимизатор решит, что будет более эффективно сортировать данные перед вставкой, он сделает это где-то перед оператором вставки. Если вы вводите сортировку как часть вашего запроса, оптимизатор должен понимать, что данные уже отсортированы, и не делать это снова. Обратите внимание, что выбранный план выполнения может варьироваться от запуска к запуску в зависимости от количества строк, вставленных в промежуточную таблицу.
Если вы можете фиксировать планы выполнения процесса с явной сортировкой и без нее, прикрепите их к своему вопросу для комментариев.
Изменить: 2011-10-28 17:00
Ответ @ Gonsalu, кажется, показывает, что операция сортировки всегда происходит, это не так. Требуются демонстрационные сценарии!
Поскольку сценарии становились достаточно большими, я переместил их в Gist . Для простоты экспериментов сценарии используют режим SQLCMD. Тесты проводятся на 2K5SP3, двухъядерный, 8 ГБ.
Тесты на вставку охватывают три сценария:
Первый запуск, вставив 25 строк.
Все три плана выполнения одинаковы, нигде в плане не происходит сортировки, и сканирование кластеризованного индекса имеет вид «order = false».
Второй запуск, вставка 26 строк.
На этот раз планы отличаются.
Таким образом, существует переломный момент, когда оптимизатор считает, что это необходимо. Как показывает @MartinSmith, похоже, что это основано на оценочных строках, которые нужно вставить. На моем тестовом стенде 25 не требует сортировки, 26 - (2K5SP3, двухъядерный, 8 ГБ)
Сценарий SQLCMD включает переменные, которые позволяют изменять размер строк в таблице (изменение плотности страниц) и количество строк в dbo.MyTable перед дополнительными вставками. Из моих испытаний ни один не влияет на переломный момент.
Если кто-то из читателей так склонен, пожалуйста, запустите сценарии и добавьте свой переломный момент в качестве комментария. Интересно узнать, меняется ли он в зависимости от тестовых установок и / или версий.
Изменить: 2011-10-28 20:15
Повторные испытания на той же установке, но с 2K8R2. На этот раз переломный момент составляет 251 ряд. Опять же, изменение плотности страниц и количества существующих строк не имеет никакого эффекта.
источник
ORDER BY
Пункт вSELECT
заявлении является излишним.Это избыточно, потому что строки, которые будут вставлены, если они должны быть отсортированы , все равно сортируются.
Давайте создадим контрольный пример.
Давайте включим текстовое отображение фактических планов запросов, чтобы мы могли видеть, какие задачи выполняет обработчик запросов.
Теперь давайте
INSERT
2K строк в таблицу безORDER BY
предложения.Фактический план выполнения для этого запроса следующий.
Как вы можете видеть, оператор Sort существует до того, как произойдет фактическая вставка.
Теперь давайте очистим таблицу и
INSERT
2k строк в таблице сORDER BY
предложением.Фактический план выполнения для этого запроса следующий.
Обратите внимание, что это тот же план выполнения, который использовался для
INSERT
оператора безORDER BY
предложения.Теперь
Sort
операция не всегда обязательна, как показал Марк Смит в другом ответе (если число вставляемых строк невелико), но в этом случаеORDER BY
предложение все еще избыточно, поскольку даже при явномORDER BY
указанииSort
операция не генерируется. обработчиком запросов.Вы можете оптимизировать
INSERT
оператор в таблицу с кластеризованным индексом, используя минимально зарегистрированные данныеINSERT
, но это выходит за рамки этого вопроса.Обновлено 2011-11-02: Как показал Марк Смит ,
INSERT
для таблицы s с кластеризованным индексом не всегда требуется сортировка -ORDER BY
хотя в этом случае это предложение также является избыточным.источник