Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

195

Quando quero que uma coluna tenha valores distintos, posso usar uma restrição

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

ou eu posso usar um índice único

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

create unique index I_t2 on t2(code);

As colunas com restrições exclusivas parecem ser boas candidatas a índices exclusivos.

Existem razões conhecidas para usar restrições exclusivas e não usar índices exclusivos?

bernd_k
fonte
9
eles são realmente diferentes? Eu acho que em alguns bancos de dados, por exemplo, postgresql, uma restrição única simplesmente cria um índice exclusivo. Não estou respondendo porque não sei nada sobre servidor sql.
Xenoterracide
6
no postgresql, você pode usar uma expressão em um índice exclusivo, mas não em uma restrição exclusiva.
Neil McGuigan
1
No MS SQL, eles são implementados da mesma forma. Tente criar duas tabelas com os mesmos dados, uma com uma restrição exclusiva e a outra com um índice exclusivo. Eles usarão a mesma quantidade de espaço de índice e ambos poderão procurar no índice exclusivo que (na prática) é criado de qualquer maneira.
Jon of All Trades

Respostas:

153

Sob o capô, uma restrição exclusiva é implementada da mesma maneira que um índice exclusivo - é necessário um índice para atender com eficiência o requisito de impor a restrição. Mesmo que o índice seja criado como resultado de uma restrição UNIQUE, o planejador de consultas poderá usá-lo como qualquer outro índice, se considerar a melhor maneira de abordar uma determinada consulta.

Portanto, para um banco de dados que ofereça suporte a ambos os recursos, a escolha de qual usar usará frequentemente com estilo e consistência preferidos.

Se você planeja usar o índice como um índice (ou seja, seu código pode ser rápido para pesquisar / classificar / filtrar nesse campo), eu explicitamente usaria um índice exclusivo (e comentaria a fonte) em vez de uma restrição para fazer isso clear - dessa maneira, se o requisito de exclusividade for alterado em uma revisão posterior do aplicativo que você (ou algum outro codificador) saberá para garantir que um índice não exclusivo seja colocado no lugar do único (apenas remover uma restrição exclusiva removeria o índice completamente). Além disso, um índice específico pode ser nomeado em uma dica de índice (ie WITH (INDEX (ix_index_name)), o que não acho que seja o caso do índice criado nos bastidores para gerenciar a exclusividade, pois é improvável que você saiba seu nome.

Da mesma forma, se você precisar apenas aplicar a exclusividade como regra de negócios, e não o campo que precisa ser pesquisado ou usado para classificação, eu usaria a restrição novamente para tornar o uso pretendido mais óbvio quando alguém examinar sua definição de tabela.

Observe que, se você usar uma restrição exclusiva e um índice exclusivo no mesmo campo, o banco de dados não será brilhante o suficiente para ver a duplicação; portanto, você terminará com dois índices que consumirão espaço extra e desacelerarão as inserções / atualizações de linhas.

David Spillett
fonte
1
Eu estou querendo saber sobre o "banco de dados não será brilhante o suficiente"? Isso é verdade para todos os RDBMS? É mandatado pelo SQL-Standard? E mesmo que seja (e eu gostaria de saber por que deveria ser), todas as implementações implementam dessa maneira? Ou: por que um banco de dados não pode ser "brilhante" o suficiente?
Jürgen A. Erhard
4
@ Jae: um DBMS certamente poderia ser brilhante o suficiente, mas você teria que verificar com cada DBMS para ver se é. Se você pedir ao MSSQL para criar dois índices idênticos, ele criará dois em vez de um referido por dois nomes (pelo menos foi o caso da última vez que vi uma situação como essa (devido a um erro de copiar e colar da minha parte)), então, suponho que o mesmo seja o caso se um dos índices estiver presente devido a uma restrição.
precisa saber é o seguinte
3
+1 @ David Spillett Acho que basicamente o DBMS apenas supõe que você saiba o que está fazendo; Se você deseja criar o mesmo índice duas vezes, isso não o questiona.
Andrew Barber
2
muito perspicaz. Você sabe se esse comportamento também está no MySQL e no Apache Derby?
CorsiKa
5
Você pode nomear uma restrição e usá-la em uma dica de índice. CREATE TABLE #T(X INT CONSTRAINT PK PRIMARY KEY NONCLUSTERED);SELECT * FROM #T WITH(INDEX(PK)) WHERE X = 1. Os índices podem ser mais flexíveis, embora essas restrições não suportem todas as opções de índice, como INCLUDEcolunas d ou índices filtrados.
Martin Smith
101

Além dos pontos em outras respostas, aqui estão algumas diferenças importantes entre os dois.

Nota: As mensagens de erro são do SQL Server 2012.

Erros

A violação de uma restrição exclusiva retorna o erro 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.

A violação de um índice exclusivo retorna o erro 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.

Desativando

Uma restrição exclusiva não pode ser desativada.

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.

Mas o índice exclusivo por trás de uma restrição de chave primária ou de uma restrição exclusiva pode ser desativado, assim como qualquer índice exclusivo. Brain2000 com ponta de chapéu.

ALTER INDEX P1_u ON dbo.P1 DISABLE ;

Observe o aviso usual de que desabilitar um índice clusterizado torna os dados inacessíveis.

Opções

Restrições exclusivas oferecem suporte a opções de indexação como FILLFACTORe IGNORE_DUP_KEY, embora esse não tenha sido o caso para todas as versões do SQL Server.

Colunas incluídas

Os índices não clusterizados podem incluir colunas não indexadas (denominado índice de cobertura, este é um grande aprimoramento de desempenho). Os índices por trás das restrições PRIMARY KEY e UNIQUE não podem incluir colunas. @Ypercube.

Filtragem

Uma restrição exclusiva não pode ser filtrada.

Um índice exclusivo pode ser filtrado.

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

Restrições de chave estrangeira

Uma restrição de chave estrangeira não pode fazer referência a um índice exclusivo filtrado, embora possa fazer referência a um índice exclusivo não filtrado (acho que foi adicionado no SQL Server 2005).

Nomeação

Ao criar uma restrição, a especificação de um nome de restrição é opcional (para todos os cinco tipos de restrições). Se você não especificar um nome, o MSSQL gerará um para você.

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

Ao criar índices, você deve especificar um nome.

Gorro @ i-one.

Ligações

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

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

Andarilho de Pedra Verde
fonte
Uma restrição único pode ser desactivado e activado através do mesmo método tal como um índice: ALTER tbl ÍNDICE DE DESLIGAR uconstraint, ALTER INDEX tbl EM uconstraint RECONSTRUÇÃO
Brain2000
Obrigado @ Brain2000. Coincidentemente, eu ensinei uma seção sobre a desativação de índices nesta manhã, pouco antes de ler este comentário.
Greenstone Walker
10

Para citar o MSDN como uma fonte autorizada:

Não há diferenças significativas entre a criação de uma restrição UNIQUE e a criação de um índice exclusivo, independente de uma restrição . A validação de dados ocorre da mesma maneira e o otimizador de consulta não diferencia um índice exclusivo criado por uma restrição ou criado manualmente. No entanto, a criação de uma restrição UNIQUE na coluna torna claro o objetivo do índice ... mais informações aqui

E...

O Mecanismo de Banco de Dados cria automaticamente um índice UNIQUE para impor o requisito de exclusividade da restrição UNIQUE. Portanto, se for feita uma tentativa de inserir uma linha duplicada, o Mecanismo de Banco de Dados retornará uma mensagem de erro informando que a restrição UNIQUE foi violada e não adiciona a linha à tabela. A menos que um índice clusterizado seja especificado explicitamente, um índice exclusivo e não clusterizado é criado por padrão para impor a restrição UNIQUE ... mais informações aqui

Outro em: https://technet.microsoft.com/en-us/library/aa224827%28v=sql.80%29.aspx

user919426
fonte
6

Uma das principais diferenças entre uma restrição exclusiva e um índice exclusivo é que uma restrição de chave estrangeira em outra tabela pode fazer referência a colunas que compõem uma restrição exclusiva. Isso não é verdade para índices exclusivos. Além disso, restrições exclusivas são definidas como parte do padrão ANSI, enquanto os índices não são. Por fim, a restrição exclusiva é considerada residir no domínio do design de banco de dados lógico (que pode ser implementado de maneira diferente por diferentes mecanismos de banco de dados), enquanto o índice é um aspecto físico. Portanto, a restrição exclusiva é mais declarativa. Eu preferiria restrições únicas em quase todos os casos.

Dmitry Frenkel
fonte
8
-1 No SQL Server, o seguinte está errado: "uma restrição de chave estrangeira em outra tabela pode fazer referência a colunas que compõem uma restrição exclusiva. Isso não é verdade para índices exclusivos". No SQL Server, podemos referir as restrições do FK a índices exclusivos.
AK
4
Acho que a capacidade de uma restrição de chave estrangeira referenciar um índice exclusivo foi adicionada no SQL Server 2005. Muitas fontes, incluindo algumas páginas no BOL, não foram atualizadas para refletir as alterações, portanto, não acho que a resposta de Dmitry merece os votos negativos. O restante de sua resposta está no local - restrições são padrão ANSI, índices não.
Greenstone Walker
apesar desses votos negativos, minha resposta favorita.
miracle173
Os padrões são importantes. Se os padrões da Ansi usarem uma restrição exclusiva, devemos usar uma restrição exclusiva.
Rhyous 19/09/17
1

No Oracle, uma grande diferença é que você pode criar um índice exclusivo de função, o que não é possível com restrições exclusivas:

Por exemplo

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

Então, fk_xyzé único apenas para o registro que tem amount != 0.

Amir Pashazadeh
fonte
7
No SQL Server (a marca da pergunta), os índices podem ser filtrados com uma WHEREcláusula. CREATE UNIQUE NONCLUSTERED INDEX P4_U ON DBO.P4 ( PID ) WHERE TXT = 'qwert' ;
precisa
-3

A restrição UNIQUE é preferível ao índice UNIQUE. Quando a restrição não é exclusiva, você precisa usar um índice regular ou não exclusivo. Restrição também é outro tipo de índice. O índice é usado para acesso mais rápido.

Índices exclusivos podem ter cláusulas where. Por exemplo, você pode criar índices para cada ano com base na coluna da data

WHERE Sale_Date BETWEEN '2012-01-01' AND '2012-12-31'
Ravi Ramaswamy
fonte
É bom ver o benefício da cláusula where mencionado.
crokusek
3
"Restrição também é outro tipo de índice." Não é não. Algumas restrições (PK, UQ, FK) podem ser e são frequentemente impostas pelo uso de índices. Não necessariamente embora e não por padrão em todos os DBMS.
usar o seguinte comando