Вибір індексу кластера - PK чи FK?


11

У мене є таблиця SQL Server 2014, яка виглядає наступним чином:

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

Деякі люди з моєї команди припустили, що кластерний індекс повинен бути включений OrderId, але я думаю, що CustomerId+ OrderIdбуло б кращим вибором з наступних причин:

  • Практично всі запити будуть шукати WHERE CustomerId = @param, ніOrderId
  • CustomerIdє іноземним ключем до Customerтаблиці, тому наявність кластерного індексу з CustomerIdмає прискорити приєднання
  • Хоча CustomerIdне є унікальним, наявність додаткового OrderIdстовпчика, зазначеного в індексі, забезпечить унікальність (Ми можемо використовувати UNIQUEключове слово при створенні кластерного індексу на цих 2 стовпцях, щоб уникнути накладності неповторності)
  • Щойно дані вставляються, CustomerIdі OrderIdніколи не змінюються, тому ці рядки не рухатимуться після початкового запису.
  • Доступ до даних відбувається через ORM, який запитує всі стовпці за замовчуванням, тож коли CustomerIdнадходить запит на основі , кластерний індекс зможе надати всі стовпці без додаткової роботи.

Чи звучить підхід CustomerIdі OrderIdяк найкращий варіант з огляду на вищезазначене? Або, що саме OrderIdпо собі краще, оскільки це єдина колонка, яка гарантує унікальність сама по собі?

В даний час у таблиці є кластерний індекс OrderIdі некластеризований індекс на CustomerId, але він не охоплює, тому оскільки ми використовуємо ORM і всі стовпці запитуються, додатково потрібно їх відновити. Тому в цій публікації я намагаюся розглянути можливість підвищення продуктивності з кращим ІС.

Активність у нашій БД становить близько 85% читань та 15% записів.

Відповіді:


5

Відповідь вікі спільноти :

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

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

OrderID або OrderDate може бути краще для другого стовпця в залежності від ваших найбільш важливих запитів.

Наприклад, якщо клієнти бачать хронологічний список останніх замовлень після входу на веб-сайт, для оптимізації повинен бути наступний OrderDateORDER BY OrderDate DESC .

Якщо ви вибрали OrderID в якості кластерного індексу з некластеризованим індексом на CustomerID , ви все одно отримаєте розбиття та фрагментацію, як раз у некластерному індексі.


3

Якщо ця таблиця дуже сильно пише (наприклад, відбувається набагато більше INSERTтверджень, а не SELECTтверджень проти неї), я не погоджуся з відповіддю на wiki .

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

Якщо ви вважаєте, що CustomerID повинен бути провідним стовпцем складеного кластерного індексу, ви можете зменшити вплив розщеплення середньої сторінки, налаштувавши FILLFACTORвсі індекси цієї таблиці. Це зменшить кількість розщеплень середньої сторінки за рахунок збільшення розміру таблиці / індексу. Якщо ви хочете пройти цей маршрут, я б запропонував протестувати значення 80 і зменшити, якщо аналіз виявить, що розбиття середньої сторінки все ще вбиває ефективність.

Моя пропозиція - використовувати OrderId. OrderID, природно, має бути послідовним та генерувати більше розбіжностей на кінцевій сторінці, які хороші та очікувані при зростанні таблиці. Крім того, цей підхід буде краще грати з розділенням таблиць, якщо ви виберете використовувати стовпець OrderDate як ключ розділу. Щодо запитів, які постійно використовують поле CustomerID, створіть некластеризований індекс для обробки цих запитів. Цей індекс повинен бути визначений належним чином, FILLFACTORоскільки він буде страждати від розщеплення середньої сторінки, про яке я згадував вище, хоча вони не будуть настільки поганими на відміну від того, якщо розбиття відбувалися проти кластерного індексу.

Активність у нашій БД становить близько 85% читань та 15% записів.

CustomerID+ OrderID(і вказуючи фулфактор, щоб забезпечити зростання без розщеплення), ймовірно, краще, якщо ця оцінка справедлива. Просто переконайтесь , що оцінка точна. Тестовий тест тесту.


1
Зауважте, що вставлення замовлення для останнього (або єдиного) Клієнта на сторінку не є "розділом на середню сторінку". Тож якщо замовлення на одного клієнта великі або ширина рядків велика, то для меншої кількості вкладишів замовлення знадобиться "розбиття середньої сторінки".
Девід Браун - Microsoft
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.