Чи повинен індекс у стовпці ідентифікації не бути кластеризованим?


19

Чи слід створювати кластерний або некластеризований ПК / унікальний індекс для стовпця ідентичності для таблиці з стовпцем ідентичності?

Причина в тому, що для запитів будуть створені інші індекси. Запит, який використовує некластеризований індекс (на купі) і повертає стовпці, не охоплені індексом, використовуватиме менш логічний введення / виведення (LIO), оскільки немає додаткових кластерних кроків b-дерева пошуку кроків?

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, B 
from T 
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)

select A, B, C
from T 
where B between @a and @a+5 

....

Кластеризована ПК у стовпчику особистість хороша тим, що:

  1. Він збільшується монотонно, тому при вставлянні сторінка не розпадається. Кажуть, об'ємна вставка може бути такою ж швидкою, як на купі (некластеризований) стіл

  2. Вона вузька

Однак чи будуть запити у питанні швидшими, не встановлюючи їх кластером?

** Оновлення: ** Що робити, якщо Idє FK інших таблиць, і він буде приєднаний до деяких запитів?


3
Це не краще чи гірше, це залежить.
Аарон Бертран

1
@ypercube Посилання kejser.org/clustered-indexes-vs-heaps сказало, що у не-CI буде менше LIO.
u23432534

2
Я читав статтю в минулому, і це, безумовно, вказує на те, що є випадки для кластерного індексу і випадки для купи. Це не все чорне чи все біле.
ypercubeᵀᴹ

4
Я не впевнений, що ваша відповідь на @ypercube відповідає будь-якому з критеріїв, які цитує пан Кейсер - принаймні з деталями, якими ви поділилися. У його нинішньому вигляді я фактично не впевнений, що це призведе до корисної відповіді, оскільки це повинно охоплювати майже кожен окремий сценарій - що вже зроблено в цитованій публікації блогу. Якщо ви можете надати більше детальних відомостей про ваш конкретний сценарій, можливо, деякі відомості в публікації можуть бути застосовані.
swasheck

2
Це залежатиме від таких речей, як: а) навантаження (OLTP? OLAP? Тощо?), B) розмір (и) таблиці, в) нормальна форма, лише декілька. Ви не надали детальну інформацію про будь-який із цих факторів, тому будь-яка рекомендація базуватиметься на здогадах вашого оточення. Крім того, ви спробували профайлювати запити, які ви пропонуєте (із очищеними буферами) та отримуєте конкретні профілі вводу-виводу за конфігурацію та бачите для себе?
swasheck

Відповіді:


16

За замовчуванням ПК є кластеризованим і в більшості випадків це нормально. Однак яке питання слід задати:

  • чи повинен мій ПК бути кластеризованим?
  • який стовпець буде найкращим ключем для мого кластерного індексу?

PK та Clustered index - це дві різниці:

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

Тепер ми закінчуємо 2 питання:

  • Як я хочу однозначно ідентифікувати рядки в моїй таблиці (ПК)
  • Як я хочу зберегти його на рівні аркушів індексу (кластерний індекс)

Це залежить від того, як:

  • Ви розробляєте свою модель даних
  • ви запитуєте свої дані і пишете запити
  • ви вставляєте або оновлюєте свої дані
  • ...

По-перше, чи потрібен кластерний індекс? Якщо ви вставляєте групу, то ефективніше зберігати не упорядковані дані в HEAP (проти впорядкованих даних у кластері). Він використовує RID (ідентифікатор рядків, 8 байт), щоб однозначно ідентифікувати рядки та зберігати їх на сторінках.

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

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

Кластерний ключ індексу складається з усіх стовпців, які потрібно індексувати. Стовпчик унікального коду (4 байти) додається, якщо на ньому немає унікального обмеження (додаткове значення для дублікатів, нульове інакше). Цей індексний ключ буде зберігатися один раз для кожного рядка на рівні аркуша всіх ваших некластеризованих індексів. Деякі з них також будуть зберігатися кілька разів на проміжних рівнях (гілках) між коренем та рівнем листя дерева індексу (B-дерево). Якщо ключ занадто великий, весь некластеризований індекс збільшиться, зажадає більше пам’яті та більше IO, процесора, пам’яті,… Якщо у вас є ПК на ім’я + дата народження + країна, велика ймовірність, що цей ключ не є хорошим кандидатом. Він занадто великий для кластерного індексу. Унікальний ідентифікатор, що використовує NEWSEQUENTIALID (), зазвичай не розглядається як вузький ключ (16 байт), хоча є послідовним.

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

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

Кластерний індекс повинен бути унікальним і максимально вузьким. Кластеризований індекс не повинен змінюватися з часом і повинен вставлятися поступово.

Настав час написати деякий SQL, який створить таблицю, кластеризовані та некластеризовані індекси та обмеження.

Це все теоретично, оскільки ми не знаємо вашої моделі даних та використовуваних типів даних (A і B).


11

Для таблиці з первинним ключем (ПК) у стовпчику ідентифікації вона буде кластеризована за замовчуванням. Чи може бути, як некластеризованим?

Якщо ви запитуєте, чи не повинен за замовчуванням для первинного ключа стовпця ідентифікації (зокрема) не кластеризуватися, я б сказав "ні". Більшість таблиць виграють від наявності кластерного індексу, тому введення кластера за замовчуванням для обмеження первинного ключа, ймовірно, корисне в цілому, особливо для нових користувачів SQL Server.

Як і у випадку з будь-яким варіантом, завжди є різні обставини, коли одне слід віддати перевагу перед іншим, але досвідчений DBA повинен знати про дефолт і мати можливість його замінити, коли це доречно. Також див. Відповідні запитання, коли первинний ключ слід оголосити некластеризованим? .

Чи будуть запити у питанні швидшими, не встановлюючи їх кластером?

Так, але з застереженнями.

Шукання RID дійсно ефективніше, ніж ключові підходи. Навіть якщо всі необхідні сторінки знаходяться в пам'яті (дуже ймовірно, що для верхніх рівнів індексу), існує вартість процесора, пов'язана з навігацією по кластеризованому b-дереву індексу. Як наслідок, SQL Server зазвичай може виконувати набагато більше пошукових запитів RID, ніж пошук ключів на одиницю часу процесора.

Коваджі

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

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

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

Мій власний досвід показав, що дуже часто вигідно мати унікальні кластерні індекси на стовпцях ідентичності. Я виявив купи проблемними в плані управління простором, і я також повинен зазначити, що для деяких функцій SQL Server потрібен унікальний кластерний індекс, щоб функціонувати.


8

Насправді вам не потрібен індекс кластеру, ані первинний ключ, щоб створити унікальні індекси та не унікальні індекси. SQL Server підтримує кластерний індекс щонайменше з версією 1.1, але первинний ключ був лише «концепцією», яку програмісти застосували, визначивши унікальний індекс.

Але здається, що і первинні ключі, і кластерні індекси є цінними поняттями у більшості баз даних.

Давайте розглянемо документацію на SQL Server, щоб побачити часткові описи деяких параметрів індексації, як показано нижче.

Індекс кластера: https://msdn.microsoft.com/en-us/library/ms190457.aspx

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

Первинний ключ: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Таблиця може містити лише одне ПЕРШИЧНЕ КЛЮЧЕ обмеження.

  • Усі стовпці, визначені у межах обмеження PRIMARY KEY, повинні бути визначені як NOT NULL.

  • Первинний ключ можна створити як кластерний індекс (за замовчуванням, якщо немає кластерного індексу) або некластеризований індекс.

Унікальний індекс: https://msdn.microsoft.com/en-us/library/ms187019.aspx

  • Коли ви створюєте UNIQUE обмеження, створюється унікальний некластеризований індекс для забезпечення обмеження UNIQUE за замовчуванням.

  • Ви можете вказати UNIQUE Clustered Index, якщо кластерний індекс ще не існує для таблиці.

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

Коли мені вигідно, щоб первинний ключ був окремим від кластеру індексу?

Можливо, коли кластерний індекс є широким (наприклад, 5 стовпців текстової інформації, але первинний ключ невеликий (INT або BIGINT), як ви, схоже, описуєте.

  • Широкий кластерний індекс дозволить вам швидко вибирати рядки з індексу для підмножини запитів, які надають послідовні відповіді з індексу кластеру (також відомий як Таблиця ). Наприклад, 5-стовпний кластерний індекс підтримував би сканування стовпців C1, C2, C3, C4, C5 або C1, C2, C3, C4 і так далі до C1.
  • Примітка: Якщо рядки були великими, це може принести певні переваги швидкості вибору послідовного набору рядків, особливо якщо в набір результатів регулярно включаються інші стовпці таблиці.
  • У такому випадку ви можете використовувати Первинний ключ для референтної цілісності, щоб надати необхідне значення як Зовнішній ключ для обмеження рядків в інших таблицях. PK невеликий, тому ФК - це невелике враження щодо розміру таблиці (таблиць), на яку посилаються.
  • Однак зауважте, що будь-який індекс, створений у таблиці з кластерним індексом, буде включати всі стовпці кластерів в інших індексах, які ви створюєте в цій таблиці. Широкий кластерний індекс збільшить розмір усіх некластеризованих індексів цієї таблиці.

Чи варто зробити Первинним ключем лише індекс кластера?

  • Якщо у вас невеликий первинний ключ (INT або BIGINT), і це індекс кластера, накладні витрати стовпців кластера порівняно невеликі. Хоча кластерний первинний ключ у цьому випадку також буде існувати у кожному індексі цієї таблиці, платити потрібно менше, ніж обговорений вище широкий кластер.

  • Цей кластерний індекс первинного ключа зазвичай не пропонує простого шляху до серійного вибору багатьох рядків.

  • Тепер, коли ви створили первинний кластерний ключ, що з тими іншими стовпцями, які ви колись планували включити в індекс кластера ?

  • Створіть унікальний (або не унікальний) індекс за необхідності, щоб проіндексувати ці широкі критерії пошуку стовпців C1, C2, C3, C4, C5. Значення в цьому індексі “Імітація кластеризовано” можуть служити швидшим пошуковим шляхом для цих 5 стовпців. Якщо є також неіндексований стовпець або два, які також обираються регулярно, їх можна включити до індексу INCLUDE (Doctor_Name, Diagnosis_Synopsis).

Хоча я вважаю корисними прості індекси кластеру та первинні ключі, є деякі вагомі причини для роздуму над тим, чи використовувати їх у таблиці чи в базі даних.

Чи потрібен взагалі кластерний індекс?

  • Якщо ви створюєте індекси (Унікальні індекси та Не унікальні індекси) та визначаєте Первинний ключ без накладних витрат на індекс кластеру, ви можете виявити, що більш вузькі індекси дають вам те, що вам потрібно для ваших запитів.

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

  • Без кластерного індексу ваші дані зберігатимуться як купа з ідентифікатором рядків (RID), що зовсім не є хорошим механізмом пошуку. Але, як згадувалося раніше, ви можете створити унікальні та не унікальні індекси для обробки ваших запитів.

Що тепер вас бере на розгляд Heaps:

Купи та покажчики: https://msdn.microsoft.com/en-us/library/hh213609.aspx

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

Але якщо у вас також є деякі "гарячі точки" у великому наборі даних, ви також можете переглянути інший тип індексу:

Відфільтрований індекс: https://msdn.microsoft.com/en-us/library/cc280372.aspx

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

  • Фільтровані індекси мають ряд обмежень, які викладені у посиланні на відфільтровані індекси.

Однак якщо вам цікаво подумати над цією можливістю взагалі пропустити первинні ключі та кластерні індекси, ви можете прочитати посилання Маркуса Вінанда, пов’язане нижче. Він демонструє свої причини за допомогою деяких зразків коду, що дозволяє припустити, що часом можна було б відмовитися від використання цих функцій.

http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key

Але все це нарешті повертається до розуміння вашої програми та створення коду, таблиць, індексів тощо, щоб відповідати роботі, яку ви виконуєте.


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

-2

Пару пунктів, які слід врахувати.

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

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

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


Наскільки високою є ставка, щоб це фактично стало проблемою?
ypercubeᵀᴹ

@ypercube чи можу я сказати "це залежить"? Тому що це робить. За відсутності тригерів на столі я б очікував, що я почне відчувати певну суперечку з десяток ниток загальною сумою 1К вставок за секунду.
mustaccio


Я не погоджуюся, але мене запитували, як далеко можна пройти за допомогою однієї гарячої точки. Я пам'ятаю, як бачив статтю про вставлення 30K рядків на секунду в таблицю з IDENTITY як CI (якщо пам'ять служить мені добре), але я не можу знайти допис у блозі.
ypercubeᵀᴹ

Ця дискусія є безглуздою за відсутності конкретного робочого навантаження, що відповідає конкретній схемі конкретного обладнання. Я сподіваюся, що всі ми можемо погодитися, що індекс монотонно зростаючої послідовності створить "гарячу точку"; чи створить це неприйнятне вузьке вузьке місце і чи варто дбати про нього чи ні, залежить від обставин.
mustaccio
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.