Кластеризовано проти не кластеризованих


98

Мої знання нижчого рівня про SQL (Server 2008) обмежені, і зараз вони ставлять під сумнів наші DBA. Дозвольте мені пояснити (я згадав очевидні твердження в надії, що я маю рацію, але якщо ви бачите щось не так, будь ласка, скажіть мені) сценарій:

У нас є таблиця, в якій розміщено "Судові ухвали" для людей. Коли я створив таблицю, (Ім'я: CourtOrder), я створив її так:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Потім я застосував некластеризований індекс до первинного ключа (для ефективності). Мої причини полягають у тому, що це унікальне поле (первинний ключ), і його слід індексувати, в основному, для цілей відбору, як ми частоSelect from table where primary key = ...

Потім я застосував CLUSTERED індекс на PersonId. Причиною було групувати замовлення для конкретної людини фізично, оскільки переважна більшість робіт - це отримання замовлень на людину. Так,select from mytable where personId = ...

Мене зараз потягнуло на це. Мені сказали, що слід класти кластерний індекс на первинний ключ, а звичайний індекс на personId. Це здається мені дуже дивним. По-перше, чому б ви поставили кластерний індекс на унікальний стовпець? що це кластеризація? Напевно, це марно трапляється кластерний індекс? Я вважав би, що звичайний індекс буде використаний в унікальній колонці. Також кластеризація індексу означатиме, що ми не можемо кластеризувати інший стовпець (Один на таблицю, правда?).

Міркування мені сказали, що я помилився, що вони вважають, що введення кластерного індексу в PersonId зробить вставки повільними. Для 5% -ного збільшення швидкості вибору ми отримаємо 95-відсоткове зниження швидкості для вставок та оновлень. Це правильно і дійсно?

Вони кажуть, що, оскільки ми кластеризуємо personId, SQL Server повинен переставляти дані коли-небудь, коли ми вставляємо або вносимо зміни до PersonId.

Тож я запитав, чому SQL має поняття КЛАСТИРОВАНИЙ ІНДЕКС, якщо це так повільно? Це так повільно, як вони говорять? Як я маю налаштувати свої індекси для досягнення оптимальної продуктивності? Я б подумав, що SELECT використовується більше, ніж INSERT ... але вони кажуть, що у нас є проблеми з блокуванням в INSERTS ...

Сподіваюся, хтось може мені допомогти.


Відповіді:


117

Відмінність кластеризованого від некластеризованого індексу полягає в тому, що кластерний індекс визначає фізичний порядок рядків у базі даних . Іншими словами, застосування кластерного індексу PersonIdозначає, що рядки будуть фізично відсортовані PersonIdв таблиці, що дозволяє пошуку індексу за цим переходити прямо до рядка (а не некластеризованого індексу, який спрямовував би вас до рядка місцеположення, додавши додатковий крок).

Тим НЕ менше, це незвично для первинного ключа не є кластерний індекс, але не чули. Проблема вашого сценарію насправді протилежна тому, що ви припускаєте: ви хочете унікальних значень у кластерному індексі, а не дублікатів. Оскільки кластерний індекс визначає фізичний порядок рядка, якщо індекс знаходиться в неповторному стовпчику, то сервер повинен додати фонове значення до рядків, у яких є дублюване ключове значення (у вашому випадку будь-які рядки з однаковим PersonId), щоб поєднане значення (ключ + фонове значення) було унікальним.

Єдине, що я б запропонував, - це не використовувати сурогатний ключ (ваш CourtOrderId) стовпчик в якості основного ключа, а замість цього використовувати складений первинний ключ PersonIdта деякі інші однозначно ідентифікуючі стовпці або набір стовпців. Якщо це неможливо (або це не практично), тоді покладіть кластерний індекс CourtOrderId.


Спасибі Адам. Отже, коли б тоді корисний кластерний індекс? Я вважав, що перевага в кластерному індексі полягає в групуванні даних, коли, наприклад, більшість запитів є в PersonID ... так що дані будуть групуватися.
Крейг

3
Його фізично не сортують PersonId. Він логічно відсортований PersonId, будь-яка невідповідність між логічним та фізичним порядком є ​​ступенем логічної фрагментації.
Мартін Сміт

1
@cdotlister Перевага індексу полягає в сортуванні даних, а не в групуванні (що передбачає дублювання даних в індексі). Хоча відмінність може здатися семантичною, у випадку кластерних індексів це не так. Якщо можливо, кластерний індекс повинен містити щось, що однозначно ідентифікує рядок, і (в ідеалі) також є найбільш часто запитуваним стовпцем або набором стовпців. Ось чому він зазвичай знаходиться на первинному ключі.
Адам Робінсон

1
@CyberSluethOmega: я не знаю; Ваше запитання не містить достатньо інформації для мене, щоб прийняти рішення. Чи потрібно мені кластерний індекс на наборі стовпців, де рядки часто додаватимуть чи видалятимуть, окрім кінця таблиці ? Ні. Але я не дуже впевнений, чому ви це просите чи чому протиріччя.
Адам Робінсон

1
@CyberSluethOmega: Інтернет може робити коментарі звукозахисними або холодними, коли вони не призначені таким чином. Ви стверджували, що я сказав, що не знаю жодних обставин, коли б кластерний індекс став чимось іншим, ніж первинний ключ, коли насправді я нічого такого не сказав. Справді, що я сказав «це незвично ..., але не нечуване», що означає , що я дійсно знаю випадків , коли це робиться.
Адам Робінсон

14

Я ні в якому разі не експерт SQL ... тому сприймайте це як погляд розробника, а не перегляд DBA.

Вставки в кластеризовані (фізично впорядковані) індекси, які не є в послідовному порядку, викликають додаткову роботу для вставок / оновлень. Крім того, якщо у вас є багато вставок одночасно, і всі вони відбуваються в одному місці, ви закінчитеся суперечкою. Ваша конкретна ефективність залежить від ваших даних та способу доступу до них. Загальне правило полягає в тому, щоб побудувати кластерний індекс за найбільш унікальним вузьким значенням вашої таблиці (як правило, ПК)

Я припускаю, що ваш PersonId не зміниться, тому оновлення тут не граються. Але розглянемо знімок з кількох рядків з PersonId 1 2 3 3 4 5 6 7 8 8

Тепер вставте 20 нових рядків для PersonId з 3. По-перше, оскільки це не унікальний ключ, сервер додає додаткові байти у ваше значення (за кадром), щоб зробити його унікальним (що також додасть додатковий простір), а потім місце, де ці місця проживання повинні бути змінені. Порівняйте це з тим, щоб вставити автоматичний приріст ПК, де вставки трапляються наприкінці. Нетехнічне пояснення, швидше за все, зводиться до цього: є менше роботи "переміщення листя", якщо це природно прогресує більш високі значення в кінці таблиці, порівняно з переробкою місця розташування існуючих елементів у цьому місці під час вставки елементів.

Тепер, якщо у вас виникають проблеми з вставками, ви, ймовірно, відразу вставите купу однакових (або подібних) значень PersonId, що викликає додаткову роботу в різних місцях по всій таблиці, і фрагментація вбиває вас. Мінус переключення на кластеризацію ПК у вашому випадку полягає в тому, якщо у вас сьогодні виникають проблеми з вставкою в PersonIds, які різняться за значенням, що поширюються по всій таблиці, якщо ви переключите кластеризований індекс на ПК і всі вставки зараз відбуваються в одну місце розташування, то проблема може насправді загостритися через збільшення концентрації суперечок. (З іншого боку, якщо ваші вставки сьогодні не розкидані по всьому, а зазвичай є у подібних областях, то проблема, ймовірно, полегшиться, переключивши кластерний індекс від PersonId до ПК, оскільки ви мінімізуєте фрагментація.)

Ваші проблеми з ефективністю повинні бути проаналізовані до вашої унікальної ситуації і приймати ці відповіді як загальні вказівки. Ваша найкраща ставка - покластися на DBA, який може підтвердити, де саме лежать ваші проблеми. Це здається, що у вас є проблеми з вмістом ресурсів, які можуть перевищувати просте налаштування індексу. Це може бути симптомом набагато більшої проблеми. (Ймовірно, проблеми з дизайном ... інакше обмеження ресурсів.)

У будь-якому випадку, удачі!


5

Деякі автори пропонують не «витрачати» CIна identityстовпчик, якщо є альтернатива, яка б корисна для запитів діапазону.

З керівних принципів проектування кластерних індексів MSDN ключ слід обирати відповідно до наступних критеріїв

  1. Може використовуватися для часто використовуваних запитів.
  2. Забезпечити високу ступінь унікальності.
  3. Може використовуватися в запитах діапазону.

Ваша CourtOrderIDколонка відповідає 2. Ваші PersonIdзустрічі 1та 3. Оскільки більшість рядків у uniqueifierбудь-якому випадку буде додано доданий, ви можете просто оголосити його унікальним і використовувати, PersonId,CourtOrderIDоскільки це буде однакової ширини, але буде більш корисним, оскільки кластеризований індексний ключ додається до всіх NCI, як локатор рядків, і це дозволить їх, щоб охопити більше запитів.

Основна проблема використання PersonId,CourtOrderIDяк CI полягає в тому, що, швидше за все, настане логічна фрагментація (а це особливо впливає на запити діапазону, яким ви намагаєтеся допомогти), тому вам потрібно буде стежити за коефіцієнтом заповнення та рівнями фрагментації та частіше виконувати обслуговування індексу.


3

Це пояснюється за таким посиланням: https://msdn.microsoft.com/en-us/ms190457.aspx

Скупчений

  • Кластеризовані індекси сортують і зберігають рядки даних у таблиці або перегляді на основі їх ключових значень. Це стовпці, що входять до визначення індексу. У таблиці може бути лише один кластерний індекс, оскільки самі рядки даних можуть бути відсортовані лише в одному порядку.

  • Єдиний раз, коли рядки даних у таблиці зберігаються у відсортованому порядку, це коли таблиця містить кластерний індекс. Коли таблиця має кластерний індекс, таблиця називається кластерною таблицею. Якщо таблиця не має кластерного індексу, її рядки даних зберігаються у не упорядкованій структурі, що називається купою.

Некластеризований

  • Некластеризовані індекси мають структуру, окрему від рядків даних. Некластеризований індекс c отримує значення некластеризованого ключа індексу, і кожен запис значення ключа має вказівник на рядок даних, що містить ключове значення .

  • Вказівник від рядка індексу в некластеризованому індексі до рядка даних називається локатором рядків. Структура локатора рядків залежить від того, зберігаються сторінки даних у купі або в кластерній таблиці. Для купи локатор рядків - це вказівник на рядок. Для кластерної таблиці локатор рядків - це кластерний індексний ключ.

  • Ви можете додати нерозбіркові стовпці до рівня листів некластеризованого індексу для обходу існуючих лімітів ключових індексів, 900 байт та 16 ключових стовпців, а також виконати повністю охоплені, проіндексовані запити.


-3

Деякий db з деяким неприємним вибором, приєднується до збереженої процедури - різниця лише в індексі

INDEXES - кластеризовані порівняно з некластеризованими

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.