Чи слід додати поле автоматичного збільшення / ідентичності до таблиці перехресних посилань лише для ПК?


9

Я додаю таку таблицю перехресних посилань до моєї бази даних SQL Server:

company_id bigint not null (FK)
org_path nvarchar (2048) not null

company_idПоле відноситься до idобласті в іншу таблицю , в якій (це первинний ключ).

Зважаючи на те, що також може бути кілька записів з однаковим company_id, будь-який первинний ключ повинен буде використовувати обидва поля. Однак я не в змозі створити ключ, використовуючи обидва поля, оскільки org_pathце занадто довго для SQL Server.

Що стосується org_path, це єдина таблиця, в якій вона існує. Є ймовірність, що запити до цієї таблиці будуть запитувати або всі записи, або всі org_pathзаписи від company_id. Або кажучи інакше, виглядає сумнівно, що ця таблиця коли-небудь буде запитуватися org_path. Крім того, навряд чи org_pathбуде оновлено, і скоріше буде вставлено і - можливо, рідко - видалено.

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

Крім того, причина в nvarchar (2048)тому, що значення має імітувати це в сторонній БД. Типовим прикладом буде щось подібне

\Translation Providers\[customer name]\[order name]\

і може містити діакритику.

Отже, моє запитання таке: чи було б ефективніше додати поле з автоматичним збільшенням idі використовувати це в поєднанні з company_idпервинним ключем, або додасть непотрібні накладні витрати - і чи має той факт, що company_idпервинний ключ в іншій таблиці, ефект тут?

Відповіді:


7

Для не унікального кластеризованого індексу comany_idлише для одного, SQL Server автоматично додасть 4-байтовий цілочисельний унікалізатор до всіх дублікатів (тобто другого та наступного для ключового значення) кластерних індексних ключів, щоб зробити його унікальним. Це не піддається користувачеві.

Перевага додавання власного унікального ідентифікатора як стовпчика вторинного ключа полягає в тому, що ви все одно можете шукати, company_idа також прагнути до окремих рядків ефективніше (використовуючи, company_id, identitycolа не company_idза допомогою залишкового предиката org_path). Тоді кластерний індекс буде унікальним company_id, identitycol, тому ніяких прихованих унікалізаторів не буде додано.

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


12

Варто враховувати, що первинний ключ та кластерний індекс - це не одне і те ж. Первинний ключ - це обмеження і стосується правил, за якими дані живуть (тобто цілісність даних); це не має нічого спільного з ефективністю / продуктивністю. Первинний ключ вимагає, щоб стовпці ключів були унікальними (у поєднанні) та НЕ 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. А оскільки це означає, що рядки не вставляються послідовно, я б вказав FILLFACTOR90. Також вам потрібно буде забезпечити регулярне обслуговування індексу, щоб зменшити фрагментацію.

Друге питання

чи впливає той факт, що 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. Так будуть діакритичні знаки, ви дійсно хочете використовувати лінгвістичні еквівалентності.



0

Для чого потрібен ПК?

Чому б просто не перейти з company_id як некластеризований індекс?

Ви сказали, що найбільше шукають у всіх записах або від company_id
Рідко оновлюється
Рідко видаляйте
org_path, це єдина таблиця, в якій він існує

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

Якщо вас турбує DRI, таблиці повинні використовувати таблицю компанії як FK для company_id


Гей. Що стосується " Чому б просто не перейти з company_id як некластеризований індекс? ": Тому що у нього було б дві нижчі сторони: 1) це буде ще 1 річ, яка займає місце, тоді як кластерний індекс - це таблиця, тому немає додаткового елемента, і 2) для отримання поля NVARCHAR все-таки знадобиться пошук RID, якщо тільки це не був INCLUDEстовпець, але це ще гірше, оскільки це просто дублювання таблиці. Правда, ПК не потрібен; важливою частиною є індекс кластеру. Але після того, як ви отримаєте ІДЕНТИТЕТ, ви також можете перейти з ПК. І, будь ласка, дивіться нове посилання у моїй відповіді для проходження по Унікалізатору 😃
Соломон Руцький

@srutzky Але це уникає 4-байтового цілочислового унікалізатора, тому я бачу, що як миття
папараццо

Маючи менше 10 к рядків, це не має значення; вам, ймовірно, потрібно бути в мільйонах рядків, перш ніж ви помітите ефект всього в 4 байти. Таким чином, для запиту "отримати всі рядки" насправді немає різниці в жодному з цих варіантів. Але для запиту "get for company_id = @param" допомога, якщо дані, фізично упорядковані company_id, фізично впорядковані, особливо коли це не потрібно робити пошук RID для кожного ряду.
Соломон Руцький

@srutzky Wash - це миття - 10K або 1G. Це просто щось для розгляду ОП.
папараццо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.