Должен ли я избавиться от кластеризованных индексов на столбцах Guid - PullRequest
31 голосов
/ 10 ноября 2008

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

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

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

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

Ответы [ 10 ]

27 голосов
/ 10 ноября 2008

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

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

Так что да, не кластеризовать индекс по GUID.

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

24 голосов
/ 10 ноября 2008

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

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

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

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

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

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

Для некластеризованного индекса он должен проходить индекс один раз для каждой извлекаемой строки ...

ПРИМЕЧАНИЕ: РЕДАКТИРОВАТЬ
Чтобы устранить проблему с последовательностью для столбцов Guid Key, имейте в виду, что SQL2k5 имеет NEWSEQUENTIALID (), которая фактически генерирует Guids «старым» последовательным способом.

или вы можете исследовать алгоритм алгоритма COMB Джимми Нильсена, который реализован в коде на стороне клиента:

направляющие COMB

5 голосов
/ 10 ноября 2008

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

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

Я предлагаю использовать SQL-запрос, подобный следующему, для измерения фрагментации, прежде чем принимать какие-либо решения (извините, за исключением синтаксиса 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;
5 голосов
/ 10 ноября 2008

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

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

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

4 голосов
/ 10 ноября 2008

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

2 голосов
/ 16 декабря 2008

Этот парень делает хорошую мысль,

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

2 голосов
/ 10 ноября 2008

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

Возможно, вы хотите, чтобы кластерные индексы ГДЕ-ТО были в вашей базе данных. Например, если у вас есть таблица «Автор» и таблица «Книга» с внешним ключом «Автор», и если в вашем приложении есть запрос, который говорит: «выберите ... из Книги, где AuthorId = .. ", тогда вы будете читать набор книг. Будет быстрее, если эти книги физически будут находиться рядом друг с другом на диске, чтобы головке диска не приходилось прыгать от сектора к сектору, собирая все книги этого автора.

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

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

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

0 голосов
/ 29 января 2013

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

0 голосов
/ 10 ноября 2008

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

0 голосов
/ 10 ноября 2008

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

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