Должен ли я создать уникальный кластерный индекс или неуникальный кластерный индекс для этой таблицы SQL 2005? - PullRequest
2 голосов
/ 01 мая 2010

У меня есть таблица, хранящая миллионы строк. Это выглядит примерно так:

Table_Docs
ID, Bigint (Identity col)
OutputFileID, int
Sequence, int
…(many other fields)

Мы попадаем в ситуацию, когда разработчик, создавший его, сделал OutputFileID кластеризованным индексом. Это не уникально. Там может быть тысячи записей с этим идентификатором. Это не имеет никакого преимущества для любых процессов, использующих эту таблицу, поэтому мы планируем удалить ее.

Вопрос в том, что изменить на… У меня есть два кандидата, столбец идентификаторов идентификаторов - естественный выбор. Тем не менее, у нас есть процесс, который выполняет множество команд обновления для этой таблицы, и для этого он использует последовательность. Последовательность не уникальна. Большинство записей содержат только одну, но около 20% могут иметь две или более записей с одинаковой последовательностью.

Приложение INSERT - это кусок грубого VB6, бросающий тысячи команд вставки в таблицу. Вставленные значения никогда не находятся в определенном порядке. Таким образом, последовательность одной вставки может быть 12345, а следующая - 12245. Я знаю, что это может привести к тому, что SQL будет перемещать много данных, чтобы поддерживать кластеризованный индекс в порядке. Однако последовательность вставок обычно близка к порядку. Все вставки будут иметь место в конце кластерной таблицы. Например: у меня есть 5 миллионов записей с последовательностью от 1 до 5 миллионов. Приложение INSERT будет вставлять последовательности в конце этого диапазона в любой момент времени. Переупорядочение данных должно быть минимальным (максимум десятки тысяч записей).

Теперь приложение UPDATE - наша звезда .NET. Это делает все ОБНОВЛЕНИЯ в столбце Sequence. “Update Table_Docs Set Feild1=This, Field2=That…WHERE Sequence =12345” - сотни тысяч таких в день. ОБНОВЛЕНИЯ являются полностью и полностью случайными, затрагивая все точки таблицы.

Все остальные процессы просто выполняют SELECT на этом (веб-страницы). Регулярные индексы охватывают те.

Итак, мой вопрос: что лучше… уникальный кластеризованный индекс для столбца ID, выгодный для приложения INSERT, или неуникальный кластеризованный индекс для последовательности, выгодный для приложения UPDATE?

Ответы [ 3 ]

4 голосов
/ 01 мая 2010

Прежде всего, я бы определенно рекомендовал бы иметь кластерный индекс!

Во-вторых, ваш кластерный индекс должен быть :

  • узкая
  • статический (никогда или почти никогда не меняется)
  • уникальный
  • постоянно растет

так что INT IDENTITY - очень продуманный выбор.

Если ваш ключ кластеризации не является уникальным, SQL Server добавит 4-байтовый уникализатор к этим значениям столбца, что сделает ваш ключ кластеризации и вместе с ним все некластеризованные индексы в этой таблице большими и менее оптимальными.

Так что в вашем случае я бы выбрал идентификатор - он узкий, статичный, уникальный и постоянно растущий - не может быть более оптимальным, чем это! Поскольку Sequence интенсивно используется в операторах UPDATE, определенно добавьте в него некластеризованный индекс!

См. Отличные сообщения в блоге Кимберли Триппа о выборе правильного ключа кластеризации для получения дополнительной справочной информации по теме.

2 голосов
/ 01 мая 2010

Как правило, вы хотите, чтобы ваш кластерный индекс был уникальным. Если это не так, SQL Server фактически добавит к нему скрытый «унивификатор», чтобы сделать его уникальным, и это увеличивает накладные расходы.

Итак, вам лучше всего использовать столбец ID в качестве индекса.

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

1 голос
/ 01 мая 2010

Самое плохое в вставках не по порядку - это разбиение на страницы.

Когда SQL Server необходимо вставить новую запись в существующую страницу индекса и не найти там места, она берет половину записей со страницы и перемещает их в новую.

Скажем, у вас есть записи, заполняющие всю страницу:

1 2 3 4 5 6 7 8 9

и нужно вставить 10. В этом случае SQL Server просто запустит новую страницу.

Однако, если у вас есть это:

1 2 3 4 5 6 7 8 11

, 10 должно идти до 11. В этом случае SQL Server переместит записи с 6 на 11 на новую страницу:

6 7 8 9 10 11

Старая страница, как это легко увидеть, останется наполовину заполненной (туда попадут только записи с 1 до 6, которые очень).

Это увеличит размер индекса.

Давайте создадим две таблицы примеров:

CREATE TABLE perfect (id INT NOT NULL PRIMARY KEY, stuffing VARCHAR(300))
CREATE TABLE almost_perfect (id INT NOT NULL PRIMARY KEY, stuffing VARCHAR(300))

;
WITH    q(num) AS
        (
        SELECT  1
        UNION ALL
        SELECT  num + 1
        FROM    q
        WHERE   num < 200000
        )
INSERT
INTO    perfect
SELECT  num, REPLICATE('*', 300)
FROM    q
OPTION (MAXRECURSION 0)

;
WITH    q(num) AS
        (
        SELECT  1
        UNION ALL
        SELECT  num + 1
        FROM    q
        WHERE   num < 200000
        )
INSERT
INTO    almost_perfect
SELECT  num + CASE num % 5 WHEN 0 THEN 2 WHEN 1 THEN 0 ELSE 1 END, REPLICATE('*', 300)
FROM    q
OPTION (MAXRECURSION 0)

EXEC sp_spaceused N'perfect'
EXEC sp_spaceused N'almost_perfect'

perfect         200000   66960 KB    66672 KB    264 KB  24 KB
almost_perfect  200000   128528 KB   128000 KB   496 KB  32 KB

Даже при вероятности выхода из строя только 20% таблица становится вдвое больше.

С другой стороны, наличие кластерного ключа на Sequence уменьшит I/O в два раза (поскольку это можно сделать с помощью одного кластеризованного поиска индекса, а не двух некластеризованных).

Таким образом, я бы взял примерное подмножество ваших данных, вставил бы их в тестовую таблицу с кластеризованным индексом на Sequence и измерил размер результирующей таблицы.

Если он меньше чем в два раза размер той же таблицы с индексом на ID, я бы пошел на кластеризованный индекс на Sequence (так как итоговое значение I/O будет меньше).

Если вы решили создать кластеризованный индекс на Sequence, сделайте ID некластеризованным PRIMARY KEY и сделайте кластеризованный индекс UNIQUE на Sequence, ID. Это будет использовать значимый ID вместо непрозрачного уникального.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...