2010-08-20 1 views
6

У нас есть устаревшая база данных, которая является SQL-сервером db (2005 и 2008).База данных сервера Sql для кластеризованного индекса или нет

Все первичные ключи в таблицах - это UniqueIdentifiers.

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

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

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

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

т.е.

INT идентичность - Первая колонка для поддержания скорости вставки уникальный идентификатор - Для того, чтобы обеспечить приложение продолжает работать, как ожидалось.

Цель состоит в том, чтобы улучшить запрос идентификации и объединить производительность таблицы.

Q1: Будет ли это улучшать производительность запроса в db или замедлит его?

Q2: Есть ли альтернатива этому, которого я не перечислял?

Благодаря Пита

Edit: Производительность вопросы по получению данных быстро через оператор выбора, особенно если некоторые из более «транзакционного/изменений» таблицы соединяются вместе.

Редактирование 2: Соединения между таблицами обычно заключаются между основным ключом и внешними ключами, для таблиц с внешними ключами они включены в некластеризованный индекс, чтобы обеспечить более индекс покрытия.

В таблицах нет других значений, которые бы обеспечивали хороший сгруппированный индекс.

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

Редактирование 3: Я бы оценил, что 80% запросов выполняются только на первичных и внешних ключах через механизм доступа к данным. Как правило, наша модель данных имеет ленивые загружаемые объекты, которые выполняют запрос при обращении, эти запросы используют идентификатор объектов и столбец PK. У нас есть большое количество запросов на исключение/включение данных, управляемых пользователем, которые используют столбцы внешнего ключа в качестве фильтра, основанного на критериях для типа X, исключают следующие идентификаторы. Оставшиеся 20% - это те, где указаны столбцы Enum (int) или диапазона дат, в системе выполняется очень мало текстовых запросов.

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

+0

У вас в настоящее время есть некластеризованный индекс для уникальных идентификаторов? – jwsample

+0

Да, у нас есть некластеризованные индексы для уникальных идентификаторов. – Peter

+0

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

ответ

4

Если у вас нет кластерного индекса в таблице, он хранится как куча, а не b-дерево. Доступ к данным Heap абсолютно ужасен в SQL Server, поэтому вам обязательно нужно добавить кластерный индекс.

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

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

+0

Blue, к сожалению, я не могу опубликовать модель данных, так как моя компания чрезвычайно строга, когда дело доходит до такого рода вещей. В некоторых таблицах есть столбцы даты, которые используются для сканирования диапазона. Как правило, первичные ключи (guids) и внешние ключи (guids) используются для соединений, никаких соединений в столбцах с открытым текстом нет. Мне было интересно использовать созданную дату, но я только что добавил, что в последней версии и, следовательно, не каждая строка имеет это значение. Я думаю, что добавление искусственного целочисленного ключа с включенным идентификатором - это путь, который я возьму. Руководство представляет собой ПК в каждом столе. – Peter

+0

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

+0

Что бы вы ни выбрали, обязательно изучите также некластеризованные индексы. Если ваш индекс GUID содержит только столбец GUID, это может быть не очень полезно. Возможно, вам захочется исследовать добавление некоторых столбцов в предложение INCLUDE, чтобы охватить ваши наиболее распространенные запросы. –

2

Я не знаю, откуда взялись ваши GUID, но если они создаются во время вставки, использование NEWSEQUENTIALID() в SQL Server вместо NEWID() поможет вам избежать проблем с фрагментацией во время вставки.

Что касается выбора кластерного индекса, то, как утверждает Кимберли Л. Трипп, here: «Наиболее важные факторы при выборе кластерного индекса заключаются в том, что он уникален, узкий и статичный (все возрастающее имеет другие преимущества для минимизации расщеплений). " GUID не соответствует узкому требованию по сравнению с INT или даже BIGINT.

У Кимберли также есть отличная статья о GUIDs as PRIMARY KEYs and/or the clustering key.

+0

Идентификаторы генерируются через .Net Frameworks Guid.NewGuid(); поскольку архитектура этой системы была построена так, чтобы объекты генерировали свой собственный идентификатор. (Снова устаревшая система.) – Peter

0

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

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

+0

Вы правы bob Я отредактировал сообщение. Проблемы возникают, когда мы запрашиваем больше транзакционных таблиц (т. Е. Те, которые больше не изменяют статические таблицы). Это усугубляется, если мы объединяем несколько транзакционных таблиц вместе. – Peter

1

Это не на 100% ясный для меня: ваш шаблон доступа номер 1 запрашивает таблицы по идентификатору GUID или другим столбцам? И когда вы присоединяетесь к другим таблицам, какие столбцы (и типы данных) чаще всего используются?

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

UPDATE

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

Что касается использования Guid.NewGuid(), кажется, что вы можете делать sequentialGUIDs на C# в конце концов. Я нашел следующий код здесь на SO:

[DllImport("rpcrt4.dll", SetLastError = true)] 
static extern int UuidCreateSequential(out Guid guid); 

public static Guid SequentialGuid() 
{ 
    const int RPC_S_OK = 0; 
    Guid g; 
    if (UuidCreateSequential(out g) != RPC_S_OK) 
     return Guid.NewGuid(); 
    else 
     return g; 
} 

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

+0

Я отредактировал исходное сообщение, см. Править 2 и 3. – Peter

+0

Поверхностный фактор, безусловно, возможен, хотя снова он раздувает ваш индекс. Наличие ключей GUID в вашем кластерном индексе не является идеальным, но поскольку вы уже застряли с идентификаторами GUID, и они используются для большинства ваших объединений, вам, возможно, придется просто пойти с ним. Я думаю, что нижняя строка - это то, что вам нужно провести некоторое тестирование, чтобы выяснить лучший способ. У вас есть тестовая система, которую вы можете использовать для тестирования различных методов? –

+0

Я согласен, что это отстой, чтобы использовать эти огромные GUID, и снижение количества строк на странице путем уменьшения fillfactor является неудачным, но если он хочет улучшить производительность обновления за счет производительности чтения, это путь. Это даже не так прямо, как предложение, потому что разбиение страницы уже уменьшает плотность строк ... – ErikE