Должен ли я избавиться от кластеризованных индексов на столбцах Guid

Я работаю над базой данных, которая обычно использует GUID в качестве первичных ключей.

по умолчанию SQL Server помещает кластеризованный индекс в столбцы первичного ключа. Я понимаю, что это глупая идея для столбцов GUID, и что некластеризованные индексы лучше.

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

Почему бы тюнер производительности SQL не предложить это в качестве рекомендации?

10 ответов


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

Что-то вроде GUID, хотя отлично подходит для первичного ключа, может быть положительно вредным для производительности, так как будут дополнительные затраты на вставки и никакой ощутимой выгоды от выбора.

да, не кластерный индекс идентификатор GUID.

Что касается того, почему это не предлагается в качестве рекомендации, я бы предложил, чтобы тюнер знал об этом факте.


вы почти наверняка хотите создать кластеризованный индекс для каждой таблицы в вашей базе данных. Если таблица не имеет кластеризованного индекса, это то, что называется "кучей", а производительность большинства типов распространенных запросов -меньше для кучи, чем для кластеризованного индекса таблицы.

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

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

причина всего этого основана на понимании внутренней структуры индекса базы данных. Эти индексы называются сбалансированным-дерева (B-дерево) индексы. они похожи на двоичное дерево, за исключением того, что каждый узел в дереве может иметь произвольное количество записей (и дочерних узлов), а не только два. Что отличает кластеризованный индекс, так это то, что листовые узлы в кластеризованном индексе являются фактические страницы данных физического диска самой таблицы. в то время как листовые узлы некластеризованного индекса просто "указывают" на страницы данных таблиц.

когда таблица имеет clsutered индекс, поэтому страницы данных таблиц являются уровнем листа этого индекса, и каждый из них имеет указатель на предыдущую страницу и следующую страницу в порядке индекса (они образуют дважды связанный список).

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

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

ПРИМЕЧАНИЕ: EDIT
Чтобы устранить последовательную проблему для ключевых столбцов Guid, имейте в виду, что SQL2k5 имеет NEWSEQUENTIALID (), который фактически создайте GUID" старый " последовательный способ.

или вы можете исследовать Jimmy Nielsens COMB guid algotithm, который реализован в коде на стороне клиента:

гребень Guids


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

обратите внимание, что если вы используете SQL Server 2005,newsequentialid () производит последовательный GUIDs. Это помогает предотвратить проблему фрагментации.

Я предлагаю использовать SQL-запрос, как показано ниже, для измерения фрагментации перед принятием каких-либо решений (извините синтаксис non-ANSI):

SELECT OBJECT_NAME (ips.[object_id]) AS 'Object Name',
       si.name AS 'Index Name',
       ROUND (ips.avg_fragmentation_in_percent, 2) AS 'Fragmentation',
       ips.page_count AS 'Pages',
       ROUND (ips.avg_page_space_used_in_percent, 2) AS 'Page Density'
FROM sys.dm_db_index_physical_stats 
     (DB_ID ('MyDatabase'), NULL, NULL, NULL, 'DETAILED') ips
CROSS APPLY sys.indexes si
WHERE si.object_id = ips.object_id
AND   si.index_id = ips.index_id
AND   ips.index_level = 0;

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

впрочем, с целым основе кластерных индексов, чисел, как правило, последовательно (как с IDENTITY spec), поэтому они просто добавляются в конец, и данные не нужно перемещать.

С другой стороны, кластеризованные индексы не всегда плохо с GUIDs... все зависит от потребностей вашего приложения. Если вам нужно иметь возможность SELECT быстро записывает, затем использует кластеризованный индекс... the INSERT скорость будет страдать, но SELECT скорость будет улучшена.


Если вы используете NewId (), вы можете переключиться на NewSequentialId (). Это должно помочь вставить перф.


Да, нет смысла иметь кластеризованный индекс на случайном значении.

вероятно, вам нужны кластеризованные индексы где-то в вашей базе данных. Например, если у вас есть таблица" автор "и таблица" книга "с внешним ключом к" автору", и если у вас есть запрос в вашем приложении, который говорит: "выберите ... из книги, где номер = ..- тогда вы будете читать книги. Это будет быстрее, если эти книги физически находятся рядом друг с другом на диске, так что диск голова не должна прыгать из сектора в сектор, собирая все книги этого автора.

Итак, вам нужно подумать о своем приложении, о том, как оно запрашивает базу данных.

внести изменения.

и затем проверить, потому что вы никогда не знаете...


этот парень делает хорошую точку,

http://randommadness.blogspot.com/2008/07/guids-and-clustered-indexes.html


Да, вы должны удалить кластеризованный индекс на первичных ключах GUID по причинам, указанным выше. Мы сделали это на наших заявках.


Это зависит от того, делаете ли вы много вставок, или если вам нужен очень быстрый поиск по ПК.


Как уже упоминалось, избегайте использования случайного идентификатора в кластеризованном индексе-вы не получите преимуществ кластеризации. На самом деле, вы испытаете увеличенную задержку. Избавиться от них-хороший совет. Также имейте в виду, что newsequentialid() может быть чрезвычайно проблематичным в сценарии репликации с несколькими мастерами. Если базы данных A и B вызывают newsequentialid() перед репликацией, возникает конфликт.