Порядок значений вставленный в кластеризованный индекс, безусловно, влияет на производительность индекса, потенциально создавая много фрагментации, а также влияет на производительность самой вставки.
Я построил тест-кровать, чтобы увидеть, что происходит:
USE tempdb;
CREATE TABLE dbo.TestSort
(
Sorted INT NOT NULL
CONSTRAINT PK_TestSort
PRIMARY KEY CLUSTERED
, SomeData VARCHAR(2048) NOT NULL
);
INSERT INTO dbo.TestSort (Sorted, SomeData)
VALUES (1797604285, CRYPT_GEN_RANDOM(1024))
, (1530768597, CRYPT_GEN_RANDOM(1024))
, (1274169954, CRYPT_GEN_RANDOM(1024))
, (-1972758125, CRYPT_GEN_RANDOM(1024))
, (1768931454, CRYPT_GEN_RANDOM(1024))
, (-1180422587, CRYPT_GEN_RANDOM(1024))
, (-1373873804, CRYPT_GEN_RANDOM(1024))
, (293442810, CRYPT_GEN_RANDOM(1024))
, (-2126229859, CRYPT_GEN_RANDOM(1024))
, (715871545, CRYPT_GEN_RANDOM(1024))
, (-1163940131, CRYPT_GEN_RANDOM(1024))
, (566332020, CRYPT_GEN_RANDOM(1024))
, (1880249597, CRYPT_GEN_RANDOM(1024))
, (-1213257849, CRYPT_GEN_RANDOM(1024))
, (-155893134, CRYPT_GEN_RANDOM(1024))
, (976883931, CRYPT_GEN_RANDOM(1024))
, (-1424958821, CRYPT_GEN_RANDOM(1024))
, (-279093766, CRYPT_GEN_RANDOM(1024))
, (-903956376, CRYPT_GEN_RANDOM(1024))
, (181119720, CRYPT_GEN_RANDOM(1024))
, (-422397654, CRYPT_GEN_RANDOM(1024))
, (-560438983, CRYPT_GEN_RANDOM(1024))
, (968519165, CRYPT_GEN_RANDOM(1024))
, (1820871210, CRYPT_GEN_RANDOM(1024))
, (-1348787729, CRYPT_GEN_RANDOM(1024))
, (-1869809700, CRYPT_GEN_RANDOM(1024))
, (423340320, CRYPT_GEN_RANDOM(1024))
, (125852107, CRYPT_GEN_RANDOM(1024))
, (-1690550622, CRYPT_GEN_RANDOM(1024))
, (570776311, CRYPT_GEN_RANDOM(1024))
, (2120766755, CRYPT_GEN_RANDOM(1024))
, (1123596784, CRYPT_GEN_RANDOM(1024))
, (496886282, CRYPT_GEN_RANDOM(1024))
, (-571192016, CRYPT_GEN_RANDOM(1024))
, (1036877128, CRYPT_GEN_RANDOM(1024))
, (1518056151, CRYPT_GEN_RANDOM(1024))
, (1617326587, CRYPT_GEN_RANDOM(1024))
, (410892484, CRYPT_GEN_RANDOM(1024))
, (1826927956, CRYPT_GEN_RANDOM(1024))
, (-1898916773, CRYPT_GEN_RANDOM(1024))
, (245592851, CRYPT_GEN_RANDOM(1024))
, (1826773413, CRYPT_GEN_RANDOM(1024))
, (1451000899, CRYPT_GEN_RANDOM(1024))
, (1234288293, CRYPT_GEN_RANDOM(1024))
, (1433618321, CRYPT_GEN_RANDOM(1024))
, (-1584291587, CRYPT_GEN_RANDOM(1024))
, (-554159323, CRYPT_GEN_RANDOM(1024))
, (-1478814392, CRYPT_GEN_RANDOM(1024))
, (1326124163, CRYPT_GEN_RANDOM(1024))
, (701812459, CRYPT_GEN_RANDOM(1024));
Первый столбец является первичным ключом, и, как вы можете увидеть значения перечислены в случайном (иш) порядке. Перечисляя значения в произвольном порядке должны сделать SQL Server либо:
- Сортировка данных, предварительно вставить
- Не сортировать данные, в результате чего фрагментированной таблицы.
CRYPT_GEN_RANDOM()
функция используется для генерации 1024 байт случайных данных на строку, чтобы разрешить эту таблицу, чтобы потреблять несколько страниц, которые в свою очередь, позволяет увидеть эффекты фрагментированных вставок.
После того, как вы запустите выше вставку, вы можете проверить фрагментацию, как это:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('TestSort'), 1, 0, 'SAMPLED') ips;
Запуск этого на мой SQL Server 2012 экземпляра издания Developer показывает среднюю фрагментацию 90%, что указывает на SQL Server не сортировать во время вставить.
нравственность этого частности история, вероятно, будет «когда есть сомнения, соберите, если это будет полезно». Сказав это, добавление и предложение ORDER BY
в инструкцию insert не гарантируют, что в этом порядке будут вставлены вставки. Подумайте, что произойдет, если вставку идет параллельно, в качестве примера.
В непроизводственных системах вы можете использовать флаг трассировки 2332 в качестве опции в инструкции insert для принудительного SQL Server для сортировки ввода до его вставки. @PaulWhite имеет интересную статью, Optimizing T-SQL queries that change data, охватывающую это и другие детали. Имейте в виду, что флаг трассировки не поддерживается и не должен использоваться в производственных системах, поскольку это может аннулировать вашу гарантию. В системе непроизводственной, для собственного образования, вы можете попробовать добавить это к концу INSERT
заявления:
OPTION (QUERYTRACEON 2332);
После того, как вы есть, что добавляется к вставке, посмотрите на план, вы» увидите явный вид:
![enter image description here](https://i.stack.imgur.com/k0rmc.png)
было бы замечательно, если Microsoft сделает это поддерживается флаг трассировки.
Paul White made me aware что SQL Server делает автоматически вводит оператор сортировки в план, когда он считает, что один будет полезен. Для примера запроса выше, если я запустил вставку с 250 элементами в предложении values
, сортировка не будет выполнена автоматически. Однако в 251 элементе SQL Server автоматически сортирует значения до вставки. Почему обрезание 250/251 строк остается для меня загадкой, за исключением того, что она жестко закодирована. Если я уменьшу размер данных, вставленных в столбец SomeData
, на один байт, обрезание равно еще 250/251 строк, хотя размер таблицы в обоих случаях составляет всего одну страницу. Интересно, что, глядя на вставку с SET STATISTICS IO, TIME ON;
, вставки с байтом SomeData
принимают в два раза больше времени при сортировке.
Без сортировки (т.е. 250 строк вставлено):
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 16 ms, elapsed time = 16 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
Table 'TestSort'. Scan count 0, logical reads 501, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob
read-ahead reads 0.
(250 row(s) affected)
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 11 ms.
С рода (т.е. 251 строк вставлено):
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 15 ms, elapsed time = 17 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
Table 'TestSort'. Scan count 0, logical reads 503, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob
read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob
read-ahead reads 0.
(251 row(s) affected)
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 16 ms, elapsed time = 21 ms.
После того, как вы начинаете увеличивать размер строки, отсортированный версию безусловно, становится более эффективным. При вставке 4096 байт в SomeData
сортированная вставка почти на два раза быстрее на моей тестовой установке, чем несортированная вставка.
В качестве побочного сведению, в случае, если вы заинтересованы, я сгенерировал пункт VALUES (...)
с помощью этого T-SQL:
;WITH s AS (
SELECT v.Item
FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) v(Item)
)
, v AS (
SELECT Num = CONVERT(int, CRYPT_GEN_RANDOM(10), 0)
)
, o AS (
SELECT v.Num
, rn = ROW_NUMBER() OVER (PARTITION BY v.Num ORDER BY NEWID())
FROM s s1
CROSS JOIN s s2
CROSS JOIN s s3
CROSS JOIN v
)
SELECT TOP(50) ', ('
+ REPLACE(CONVERT(varchar(11), o.Num), '*', '0')
+ ', CRYPT_GEN_RANDOM(1024))'
FROM o
WHERE rn = 1
ORDER BY NEWID();
Это генерирует 1000 случайных значений, выбирая только верхние 50 строк с уникальными значениями в первом столбце. Я скопировал и ввел вывод в выступление INSERT
.
Почему вы говорите, что «порядок сортировки индекса будет противоположным порядку сортировки значений, которые нужно вставить»? Следует ли считать, что кластерный индекс был объявлен как «DESC»? Если нет, по умолчанию используется 'ASC', который является порядком _same_ как значения, которые нужно вставить. Однако я мог бы что-то неправильно понять. –
В этом суть вопроса: что происходит, когда значение идентификатора подсчитывается, но порядок сортировки был установлен вручную для desc. Наверное, я не сделал это полностью ясным в своем посте, извините, я не являюсь носителем английского языка. – HCL
В вашей среде находятся люди, выполняющие инструкции SELECT, которые ORDER по кластерному индексу в порядке убывания? – pacreely