Варто враховувати, що первинний ключ та кластерний індекс - це не одне і те ж. Первинний ключ - це обмеження і стосується правил, за якими дані живуть (тобто цілісність даних); це не має нічого спільного з ефективністю / продуктивністю. Первинний ключ вимагає, щоб стовпці ключів були унікальними (у поєднанні) та НЕ NULL (окремо). PK застосовується за допомогою унікального індексу, хоча він може бути кластерним або не кластеризованим.
Кластерний індекс - це засіб фізичного (тобто на диску) впорядкування даних у таблиці та стосується продуктивності; це не має нічого спільного з цілісністю даних. Кластерний індекс можевимагають, щоб стовпець ключів був унікальним (у поєднанні), але цього не потрібно. Однак, оскільки кластерний індекс - це фізичний порядок даних, він повинен однозначно ідентифікувати кожен рядок незалежно від того. Отже, якщо ви не встановите його для необхідності унікальності, він створить свою власну унікальність за допомогою прихованого 4-байтового стовпця "Унікалізатор". Цей стовпець завжди є в не унікальних кластерних індексах, але він не займає місця, коли ключові поля є унікальними (у поєднанні). Щоб побачити з перших рук, як працює цей стовпчик "Унікатор" (як у кластерному індексі, так і вплив на некластеризовані індекси), будь ласка, ознайомтеся з цим тестовим сценарієм, який я розмістив у сценарії PasteBin: T-SQL, щоб перевірити розмір Uniquifier .
Отже, головне питання:
чи було б ефективнішим додати поле з автоматичним збільшенням id
і використовувати це разом із company_id
основним ключем, чи додасть це зайві накладні витрати
це поєднання цих двох понять, тому їх потрібно вирішувати окремо, хоча, безумовно, є певне збіг.
Чи IDENTITY
слід додати стовпець або це буде зайвим накладними?
Якщо ви додаєте INT IDENTITY
стовпець і використовуєте його для створення ПК, припускаючи, що це буде ПК із кластером, що додає 4 байти в кожен рядок. Цей стовпець видимий і корисний для запитів. Він може бути доданий до інших таблиць як зовнішній ключ, хоча в цьому конкретному випадку цього не відбудеться.
Якщо ви не додаєте INT IDENTITY
стовпець, ви не можете створити ПК у цій таблиці. Однак ви все одно можете створити кластерний індекс на столі до тих пір, поки не будете використані UNIQUE
параметри. У цьому випадку SQL Server додасть прихований стовпець під назвою "Уніфікатор", який веде себе як описано вище. Оскільки стовпець прихований, його не можна використовувати в запитах або як посилання на іноземні ключі.
Що стосується ефективності, ці варіанти приблизно однакові. Так, місця буде зайнято трохи менше, якщо не унікальний кластерний індекс через деякі рядки (ті, які мають початкові унікальні значення ключа) займає 0 байт, а всі рядки в IDENTITY
/ PK займуть 4 байти. Але не буде достатньо рядків з 0 байтами (особливо, якщо очікується невелика кількість рядків), щоб коли-небудь помітити різницю, не кажучи вже про те, щоб виважити зручність можливості використання ID
стовпця в запитах.
Стовпець ІД ІДЕНТИМЕНТНОСТІ або стовпчик персистованих org_path
обчислених стовпців?
Зважаючи на те, що ви не будете шукати рядки на основі org_path
значень, то не має сенсу додавати накладні дані Персистового обчисленого стовпця плюс потрібно обчислювати цей хеш у запитах, щоб відповідати обчисленій колонці (це був мій оригінальна пропозиція, наявна в історії оновлень тут , яка базувалася на початковій редакції / деталі запитання). У цьому конкретному випадку INT IDENTITY
стовпець "Ідентифікатор", мабуть, найкращий.
Замовлення ключових стовпців
З огляду на те, що ID
стовпець рідко, якщо і колись, буде використовуватися в запитах, і враховуючи, що два основні випадки використання - це отримати або "всі рядки", або "всі рядки для заданої company_id
", я б створив ПК на company_id, id
. А оскільки це означає, що рядки не вставляються послідовно, я б вказав FILLFACTOR
90. Також вам потрібно буде забезпечити регулярне обслуговування індексу, щоб зменшити фрагментацію.
Друге питання
чи впливає той факт, що company_id є первинним ключем в іншій таблиці
Ні.
Тригер
Оскільки org_path
значення в a company_id
є унікальними, ви все одно повинні створити тригер INSERT, UPDATE
для його виконання. У тригері зробіть IF EXISTS
запит, який, ймовірно, робить а COUNT(*)
і GROUP BY company_id, org_path
. Якщо що-небудь знайдено, ROLLBACK
видаліть, щоб скасувати операцію DML, а потім RAISERROR
сказати, що є дублікати.
Збірка
У моїй початковій відповіді (грунтуючись на оригінальній формулюванні / розрізнені деталі запитання та доступні в історії редагувань тут ), я запропонував можливо скористатися бінарним (тобто _BIN2
) зіставленням. Тепер, коли ми маємо уявлення про те, що саме org_path
є, я б не рекомендував використовувати бінарний Collation. Так будуть діакритичні знаки, ви дійсно хочете використовувати лінгвістичні еквівалентності.