Коли я повинен використовувати унікальне обмеження замість унікального індексу?


194

Коли я хочу, щоб стовпець мав чіткі значення, я можу або використовувати обмеження

create table t1(
id int primary key,
code varchar(10) unique NULL
);
go

або я можу використовувати унікальний індекс

create table t2(
id int primary key,
code varchar(10) NULL
);
go

create unique index I_t2 on t2(code);

Стовпці з унікальними обмеженнями здаються хорошими кандидатами на унікальні індекси.

Чи є відомі причини використовувати унікальні обмеження, а не використовувати натомість унікальні індекси?


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

6
у postgresql ви можете використовувати вираз в унікальному індексі, але не в унікальному обмеженні.
Ніл Макгуйган

1
У MS SQL вони реалізовані однаково. Спробуйте створити дві таблиці з однаковими даними, одна з унікальним обмеженням, а друга з унікальним індексом. Вони будуть використовувати однакову кількість простору індексу, і обидва зможуть шукати проти унікального індексу, який (на практиці) створений у будь-якому випадку.
Йон усіх торгів

Відповіді:


153

Під капотом реалізується унікальне обмеження так само, як і унікальний індекс - індекс необхідний для ефективного виконання вимоги щодо забезпечення обмеження. Навіть якщо індекс створений в результаті UNIQUE обмеження, планувальник запитів може використовувати його, як і будь-який інший індекс, якщо він вважає його найкращим способом наближення до заданого запиту.

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

Якщо ви плануєте використовувати індекс як індекс (тобто ваш код може покладатися на швидкий пошук / сортування / фільтрацію в цьому полі), я б явно використовував унікальний індекс (і коментував джерело), ​​а не обмеження, щоб зробити це зрозуміло - таким чином, якщо вимога унікальності буде змінена в подальшому перегляді програми, ви (або якийсь інший кодер) будете знати, щоб переконатися, що замість унікального буде встановлений унікальний індекс (просто видалення унікального обмеження буде видалено індекс повністю). Також конкретний індекс може бути названий у підказці індексу (тобто WITH (INDEX (ix_index_name)), що, на мою думку, не стосується індексу, створеного за лаштунками для управління унікальністю, оскільки ви навряд чи знаєте його ім'я.

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

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


1
Мені цікаво, що "база даних не буде достатньо яскравою"? Це правда для всіх RDBMS? Це доручено стандарту SQL? І навіть якщо це так (і мені цікаво, чому це повинно бути), чи всі імплементації реалізують саме так? Або: чому БД не може бути достатньо "яскравою"?
Юрген А. Ерхард

4
@jae: СУБД, безумовно, може бути достатньо яскравою, але вам доведеться перевірити, чи є вона. Якщо ви попросите MSSQL створити два однакові індекси, він створить два, а не один, на який посилаються два імені (принаймні, так було в останній раз, коли я помітив подібну ситуацію (через помилку копіювання + вставки з мого боку)), тому я припускаю, що те саме відбувається, якщо один із індексів присутній через обмеження.
Девід Спіллетт

3
+1 @David Spillett Я думаю, що в основному СУБД передбачає, що ви знаєте, що робите; Якщо ви хочете створити один і той же індекс двічі, це не ставить під сумнів вас.
Ендрю Барбер

2
дуже проникливий. Чи знаєте ви, чи є така поведінка в MySQL та Apache Derby?
corsiKa

5
Ви можете назвати обмеження і використовувати його в підказці. CREATE TABLE #T(X INT CONSTRAINT PK PRIMARY KEY NONCLUSTERED);SELECT * FROM #T WITH(INDEX(PK)) WHERE X = 1. Індекси можуть бути більш гнучкими, хоча в цьому обмеженні не підтримуються всі параметри індексу, такі як INCLUDEd стовпці або відфільтровані індекси.
Мартін Сміт

101

Окрім пунктів в інших відповідях, ось деякі ключові відмінності між ними.

Примітка. Повідомлення про помилки надходять із SQL Server 2012.

Помилки

Порушення унікального обмеження повертає помилку 2627.

Msg 2627, Level 14, State 1, Line 1
Violation of UNIQUE KEY constraint 'P1U_pk'. Cannot insert duplicate key in object 'dbo.P1U'. The duplicate key value is (1).
The statement has been terminated.

Порушення унікального індексу повертає помилку 2601.

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.P1' with unique index 'P1_u'. The duplicate key value is (1).
The statement has been terminated.

Відключення

Унікальне обмеження неможливо відключити.

Msg 11415, Level 16, State 1, Line 1
Object 'P1U_pk' cannot be disabled or enabled. This action applies only to foreign key and check constraints.
Msg 4916, Level 16, State 0, Line 1
Could not enable or disable the constraint. See previous errors.

Але унікальний індекс, що стоїть за обмеженням первинного ключа або унікальним обмеженням, може бути відключений, як і будь-який унікальний індекс. Шапочка Brain2000.

ALTER INDEX P1_u ON dbo.P1 DISABLE ;

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

Параметри

Обмеження унікальності підтримують параметри індексування , як FILLFACTORі IGNORE_DUP_KEY, хоча це не так для кожної версії SQL Server.

Включені стовпці

Некластеризовані індекси можуть включати неіндексовані стовпці (їх називають індексом покриття, це головне підвищення продуктивності). Індекси, що стоять за обмеженнями PRIMARY KEY та UNIQUE, не можуть включати стовпці. Шапка-наконечник @ypercube.

Фільтрування

Унікальне обмеження не може бути відфільтровано.

Унікальний індекс можна відфільтрувати.

CREATE UNIQUE NONCLUSTERED INDEX Students6_DrivesLicence_u 
ON dbo.Students6( DriversLicenceNo ) WHERE DriversLicenceNo is not null ;

Зовнішні ключові обмеження

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

Іменування

Під час створення обмежень вказувати назву обмеження необов'язково (для всіх п’яти типів обмежень). Якщо ви не вкажете ім'я, MSSQL згенерує для вас.

CREATE TABLE dbo.T1 (
    TID int not null PRIMARY KEY
) ;
GO
CREATE TABLE dbo.T2 (
    TID int not null CONSTRAINT T2_pk PRIMARY KEY
) ;

Створюючи індекси, потрібно вказати ім’я.

Шапка-наконечник @ i-one.

Посилання

http://technet.microsoft.com/en-us/library/aa224827(v=SQL.80).aspx

http://technet.microsoft.com/en-us/library/ms177456.aspx


Унікальне обмеження можна відключити та включити за допомогою того ж методу, що й індекс: ALTER INDEX tbl ON unconstraint DISABLE, ALTER INDEX tbl ON unconstraint REBUILD
Brain2000

Дякую @ Brain2000. Випадково я виклав розділ про відключення індексів сьогодні вранці, перш ніж прочитати цей коментар.
Грінстоун Уокер

10

Щоб навести MSDN як авторитетне джерело:

Немає суттєвих відмінностей між створенням UNIQUE обмеження та створенням унікального індексу, незалежного від обмеження . Перевірка даних відбувається однаково, і оптимізатор запитів не розмежовує унікальний індекс, створений обмеженням, або створений вручну. Однак створення єдиного обмеження на стовпчику робить мету індексу зрозумілою ... детальніше тут

І ...

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

Інше: https://technet.microsoft.com/en-us/library/aa224827%28v=sql.80%29.aspx


6

Однією з головних відмінностей між унікальним обмеженням і унікальним індексом є те, що обмеження зовнішнього ключа в іншій таблиці може посилатися на стовпці, що складають унікальне обмеження. Це не відповідає дійсності унікальних індексів. Крім того, унікальні обмеження визначаються як частина стандарту ANSI, тоді як індекси - ні. Нарешті, унікальним обмеженням вважається жити у царині логічного дизайну баз даних (яка може бути реалізована по-різному різними двигунами БД), а індекс - фізичний аспект. Тому унікальне обмеження є більш декларативним. Я вважаю за краще унікальне обмеження майже у всіх випадках.


8
-1 У SQL Server неправильне наступне: "обмеження зовнішнього ключа в іншій таблиці може посилатися на стовпці, що складають унікальне обмеження. Це не відповідає правилам унікальних індексів". У SQL Server ми можемо віднести обмеження FK до унікальних індексів.
АК

4
Можливо, обмеження іноземного ключа посилатися на унікальний індекс було, я думаю, додане в SQL Server 2005. Багато джерел, включаючи деякі сторінки в BOL, не були оновлені, щоб відобразити зміни, тому я не думаю, що відповідь Дмитра заслуговує низових подій. Решта його відповіді на місці - Обмеження є стандартом ANSI, індекси - ні.
Greenstone Walker

незважаючи на ці голоси, моя улюблена відповідь.
чудо173

Стандарти важливі. Якщо стандартами Ansi є використання унікального обмеження, то ми повинні використовувати унікальне обмеження.
Rhyous

1

В Oracle головна відмінність полягає в тому, що ви можете створити унікальний для функцій індекс, який неможливо виконати з унікальними обмеженнями:

Наприклад

create unique index ux_test on my_table (case when amount != 0 then fk_xyz end);

Тож fk_xyzунікальний лише для записів, які є amount != 0.


7
У SQL Server (тег питання) індекси можна відфільтрувати за допомогою WHEREпункту. CREATE UNIQUE NONCLUSTERED INDEX P4_U ON DBO.P4 ( PID ) WHERE TXT = 'qwert' ;
Грінстоун Уокер

-3

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

Унікальні індекси можуть містити пропозиції. Наприклад, ви можете створювати індекси для кожного року на основі стовпця дати

WHERE Sale_Date BETWEEN '2012-01-01' AND '2012-12-31'

Приємно бачити, де згадується пільга про застереження.
crokusek

3
"Обмеження - це також інший тип індексу." Ні, це не так. Деякі обмеження (PK, UQ, FK) можуть бути і часто виконуються за допомогою використання індексів. Не обов’язково, хоча і не за замовчуванням у всіх СУБД.
ypercubeᵀᴹ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.