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

195

Когда я хочу, чтобы столбец имел разные значения, я могу использовать ограничение

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);

Столбцы с уникальными ограничениями кажутся хорошими кандидатами на уникальные индексы.

Есть ли известные причины использовать уникальные ограничения и не использовать уникальные индексы?

bernd_k
источник
9
они на самом деле разные? Я думаю, что в некоторых базах данных, например, postgresql, ограничение уникальности просто создает уникальный индекс. Я не отвечаю, потому что я ничего не знаю о сервере SQL.
ксенотеррацид
6
в postgresql вы можете использовать выражение в уникальном индексе, но не в уникальном ограничении.
Нил Макгиган
1
На MS SQL они реализованы одинаково. Попробуйте создать две таблицы с одинаковыми данными, одну с уникальным ограничением, другую с уникальным индексом. Они будут использовать одинаковое количество индексного пространства, и оба смогут искать по уникальному индексу, который (на практике) создается в любом случае.
Джон на все руки

Ответы:

153

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

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

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

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

Обратите внимание, что если вы используете как уникальное ограничение, так и уникальный индекс в одном и том же поле, база данных будет недостаточно яркой, чтобы увидеть дублирование, поэтому вы получите два индекса, которые будут занимать дополнительное пространство и замедлять вставку / обновление строк.

Дэвид Спиллетт
источник
1
Мне интересно про "база данных не будет достаточно яркой"? Это правда для всех RDBMS? Это предписано стандартом SQL? И даже если это так (и я удивляюсь, почему так должно быть), все реализации реализуют его таким образом? Или: почему БД не может быть достаточно «яркой»?
Юрген А. Эрхард
4
@jae: СУБД, конечно, может быть достаточно яркой, но вы должны проверить каждую СУБД, чтобы увидеть, если это так. Если вы попросите MSSQL создать два идентичных индекса, он создаст два, а не один, на который ссылаются два имени (по крайней мере, так было в прошлый раз, когда я обнаружил подобную ситуацию (из-за ошибки копирования + вставки с моей стороны)), поэтому я предполагаю, что то же самое имеет место, если один из индексов присутствует из-за ограничения.
Дэвид Спиллетт
3
+1 @ Дэвид Спиллетт Я думаю, что в основном СУБД предполагает, что вы знаете, что делаете; Если вам захочется создать один и тот же индекс дважды, он не будет вас об этом спрашивать.
Эндрю Барбер
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, Индексы могут быть более гибкими, хотя в этом случае ограничения не поддерживают все параметры индекса, такие как INCLUDEстолбцы d или отфильтрованные индексы.
Мартин Смит
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.

Но уникальный индекс, лежащий в основе ограничения первичного ключа или уникального ограничения, может быть отключен, как и любой уникальный индекс. Hat-tip Brain2000.

ALTER INDEX P1_u ON dbo.P1 DISABLE ;

Обратите внимание на обычное предупреждение о том, что отключение кластеризованного индекса делает данные недоступными.

Параметры

Уникальные ограничения поддерживают такие параметры индексирования, как FILLFACTORи IGNORE_DUP_KEY, хотя это было не так для всех версий SQL Server.

Включенные столбцы

Некластеризованные индексы могут включать в себя неиндексированные столбцы (называемые индексом покрытия, это значительное повышение производительности). Индексы за ограничениями PRIMARY KEY и UNIQUE не могут включать столбцы. Hat-tip @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
) ;

При создании индексов необходимо указать имя.

Hat-tip @ 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 uconstraint DISABLE, ALTER INDEX tbl ON uconstraint REBUILD
Brain2000
Спасибо @ Brain2000. По совпадению я преподавал раздел об отключении индексов этим утром перед тем, как прочесть этот комментарий.
Гринстоун Уолкер
10

Чтобы процитировать MSDN как авторитетный источник:

Нет существенных различий между созданием ограничения UNIQUE и созданием уникального индекса, который не зависит от ограничения . Проверка данных происходит таким же образом, и оптимизатор запросов не различает уникальный индекс, созданный ограничением или созданный вручную. Тем не менее, создание УНИКАЛЬНОГО ограничения на столбец проясняет цель индекса ... подробнее здесь

А также...

Компонент Database Engine автоматически создает индекс UNIQUE, чтобы обеспечить требование уникальности ограничения UNIQUE. Поэтому, если предпринята попытка вставить дублирующую строку, компонент Database Engine возвращает сообщение об ошибке, в котором говорится, что ограничение UNIQUE было нарушено, и не добавляет строку в таблицу. Если кластерный индекс не указан явно, по умолчанию создается уникальный некластеризованный индекс для применения ограничения UNIQUE ... подробнее здесь

Другое в: https://technet.microsoft.com/en-us/library/aa224827%28v=sql.80%29.aspx

user919426
источник
6

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

Дмитрий Френкель
источник
8
-1 В SQL Server неверно следующее: «ограничение внешнего ключа в другой таблице может ссылаться на столбцы, которые составляют уникальное ограничение. Это не относится к уникальным индексам». В SQL Server мы можем отнести ограничения FK к уникальным индексам.
AK
4
Я думаю, что возможность ограничения внешнего ключа ссылаться на уникальный индекс была добавлена ​​в SQL Server 2005. Многие источники, включая некоторые страницы в BOL, не были обновлены для отражения изменений, поэтому я не думаю, что ответ Дмитрия заслуживает отрицательных голосов. Остальная часть его ответа нацелена на: ограничения являются стандартом ANSI, индексы - нет.
Гринстоун Уолкер
несмотря на эти отрицательные отзывы мой любимый ответ.
чудо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

УНИКАЛЬНОЕ Ограничение предпочтительнее УНИКАЛЬНОГО Индекса. Когда ограничение не уникально, вам нужно использовать обычный или неуникальный индекс. Ограничение также является другим типом индекса. Индекс используется для более быстрого доступа.

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

WHERE Sale_Date BETWEEN '2012-01-01' AND '2012-12-31'
Рави Рамасвами
источник
Приятно видеть упомянутое преимущество.
Crokusek
3
«Ограничение - это еще один тип индекса». Нет, это не так. Некоторые ограничения (PK, UQ, FK) могут быть и часто применяются с помощью индексов. Не обязательно, хотя и не по умолчанию во всех СУБД.
ypercubeᵀᴹ