Quand devrais-je utiliser une contrainte unique au lieu d'un index unique?

195

Quand je veux qu'une colonne ait des valeurs distinctes, je peux soit utiliser une contrainte

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

ou je peux utiliser un index unique

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

create unique index I_t2 on t2(code);

Les colonnes avec des contraintes uniques semblent être de bons candidats pour des index uniques.

Existe-t-il des raisons connues d'utiliser des contraintes uniques et de ne pas utiliser d'index uniques?

Bernd_k
la source
9
sont-ils réellement différents? Je pense que dans certaines bases de données, par exemple postgresql, une contrainte unique crée simplement un index unique. Je ne réponds pas car je ne connais rien au serveur SQL.
Xenoterracide
6
dans postgresql, vous pouvez utiliser une expression dans un index unique mais pas dans une contrainte unique.
Neil McGuigan
1
Sur MS SQL, ils sont mis en œuvre de la même manière. Essayez de créer deux tables avec les mêmes données, l’une avec une contrainte unique, l’autre avec un index unique. Ils utiliseront la même quantité d’espace d’indexation et pourront tous deux rechercher l’index unique qui (dans la pratique) est créé dans les deux sens.
Jon of All Trades

Réponses:

153

Sous le capot, une contrainte unique est mise en œuvre de la même manière qu'un index unique - un index est nécessaire pour répondre efficacement à l'exigence d'appliquer la contrainte. Même si l'index est créé à la suite d'une contrainte UNIQUE, le planificateur de requêtes peut l'utiliser comme n'importe quel autre index s'il le considère comme le meilleur moyen de traiter une requête donnée.

Ainsi, pour une base de données prenant en charge les deux fonctionnalités, le choix de l’utilisation dépendra souvent du style et de la cohérence souhaités.

Si vous envisagez d’utiliser l’index comme index (c’est-à-dire que votre code peut s’appuyer sur la recherche / le tri / le filtrage sur ce champ pour être rapide), j’utiliserais explicitement un index unique (et commenter la source) plutôt qu’une contrainte pour le faire. clear - de cette façon, si l'exigence d'unicité est modifiée dans une révision ultérieure de l'application, vous (ou un autre codeur) saurez vous assurer qu'un index non unique est mis à la place de l'index unique (le seul fait de supprimer une contrainte unique aurait pour effet de supprimer l'index complètement). De plus, un index spécifique peut être nommé dans un indice (c’est-à-dire WITH (INDEX (ix_index_name))), ce qui, selon moi, n’est pas le cas pour l’index créé en arrière-plan pour gérer l’unicité, car il est peu probable que vous connaissiez son nom.

De même, si vous devez uniquement imposer l'unicité en tant que règle métier plutôt que le champ devant faire l'objet d'une recherche ou d'un tri, utilisez la contrainte, afin de rendre l'utilisation prévue plus évidente lorsque quelqu'un d'autre examine votre définition de table.

Notez que si vous utilisez à la fois une contrainte unique et un index unique sur le même champ, la base de données ne sera pas assez claire pour voir la duplication. Vous obtiendrez ainsi deux index qui consommeront de l'espace supplémentaire et ralentiront les insertions / mises à jour de lignes.

David Spillett
la source
1
Je me demande si "la base de données ne sera pas assez lumineuse"? Est-ce vrai pour tous les SGBDR? Est-ce mandaté par le standard SQL? Et même si c'est le cas (et je me demande pourquoi cela devrait l'être), est-ce que toutes les implémentations l'implémentent de cette façon? Ou: pourquoi une base de données ne peut-elle pas être assez "brillante"?
Jürgen A. Erhard le
4
@jae: un SGBD peut certes être assez brillant, mais vous devez vérifier auprès de chaque SGBD pour voir si c'est le cas. Si vous demandez à MSSQL de créer deux index identiques, il en créera deux plutôt qu'un qui est désigné par deux noms (du moins c'était le cas la dernière fois que j'ai repéré une telle situation (à cause d'une erreur copier-coller de ma part)), Je suppose donc qu'il en va de même si l'un des index est présent en raison d'une contrainte.
David Spillett
3
+1 @ David Spillett Je pense que, dans l’ensemble, le SGBD suppose simplement que vous savez ce que vous faites. Si vous avez envie de créer deux fois le même index, cela ne vous pose pas de question.
Andrew Barber
2
très perspicace. Savez-vous si ce comportement est également présent dans MySQL et Apache Derby?
CorsiKa
5
Vous pouvez nommer une contrainte et l'utiliser dans un indicateur. CREATE TABLE #T(X INT CONSTRAINT PK PRIMARY KEY NONCLUSTERED);SELECT * FROM #T WITH(INDEX(PK)) WHERE X = 1. Les index peuvent être plus flexibles dans la mesure où les contraintes ne supportent pas toutes les options d'index telles que les INCLUDEcolonnes d ou les index filtrés.
Martin Smith
101

Outre les points abordés dans d’autres réponses, voici quelques différences essentielles entre les deux.

Remarque: Les messages d'erreur proviennent de SQL Server 2012.

les erreurs

La violation d'une contrainte unique renvoie l'erreur 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.

La violation d'un index unique renvoie l'erreur 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.

Désactiver

Une contrainte unique ne peut pas être désactivée.

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.

Mais l'index unique derrière une contrainte de clé primaire ou une contrainte unique peut être désactivé, de même que tout index unique. Pointe du chapeau Brain2000.

ALTER INDEX P1_u ON dbo.P1 DISABLE ;

Notez l'avertissement habituel selon lequel la désactivation d'un index en cluster rend les données inaccessibles.

Les options

Des contraintes uniques prennent en charge des options d'indexation telles que FILLFACTORet IGNORE_DUP_KEY, bien que cela n'ait pas été le cas pour toutes les versions de SQL Server.

Colonnes Incluses

Les index non clusterisés peuvent inclure des colonnes non indexées (appelé index couvrant, il s'agit d'une amélioration majeure des performances). Les index derrière les contraintes PRIMARY KEY et UNIQUE ne peuvent pas inclure de colonnes. Hat-tip @ypercube.

Filtration

Une contrainte unique ne peut pas être filtrée.

Un index unique peut être filtré.

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

Contraintes de clé étrangère

Une contrainte de clé étrangère ne peut pas référencer un index unique filtré, bien qu'elle puisse référencer un index unique non filtré (je pense que cela a été ajouté dans SQL Server 2005).

Appellation

Lors de la création d'une contrainte, la spécification d'un nom de contrainte est facultative (pour les cinq types de contraintes). Si vous ne spécifiez pas de nom, MSSQL en générera un pour vous.

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

Lors de la création d'index, vous devez spécifier un nom.

Chapeau-pointe @ i-one.

Liens

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

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

Greenstone Walker
la source
Une contrainte unique peut être désactivée et activée via la même méthode qu'un index: ALTER INDEX tbl ON uconstraint DÉSACTIVÉ, ALTER INDEX tbl ON uconstraint REBUILD
Brain2000
Merci @ Brain2000. Par coïncidence, j'ai enseigné une section sur la désactivation des index ce matin juste avant de lire ce commentaire.
Greenstone Walker
10

Pour citer MSDN en tant que source faisant autorité:

Il n'y a pas de différence significative entre la création d'une contrainte UNIQUE et la création d'un index unique indépendant d'une contrainte . La validation des données a lieu de la même manière et l'optimiseur de requêtes ne fait pas la différence entre un index unique créé par une contrainte ou créé manuellement. Cependant, la création d'une contrainte UNIQUE sur la colonne rend l'objectif de l'index clair ... plus d'infos ici

Et...

Le moteur de base de données crée automatiquement un index UNIQUE pour appliquer l'exigence d'unicité de la contrainte UNIQUE. Par conséquent, si une tentative d'insertion d'une ligne en double est effectuée, le moteur de base de données renvoie un message d'erreur indiquant que la contrainte UNIQUE a été violée et n'ajoute pas la ligne à la table. À moins qu'un index clusterisé ne soit explicitement spécifié, un index unique, non clusterisé, est créé par défaut pour appliquer la contrainte UNIQUE ... plus d'infos ici

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

utilisateur919426
la source
6

L'une des principales différences entre une contrainte unique et un index unique réside dans le fait qu'une contrainte de clé étrangère sur une autre table peut référencer des colonnes qui constituent une contrainte unique. Ce n'est pas vrai pour les index uniques. De plus, des contraintes uniques sont définies dans le cadre de la norme ANSI, contrairement aux index. Enfin, on considère que la contrainte unique réside dans le domaine de la conception de bases de données logiques (qui peut être implémentée différemment par différents moteurs de base de données) alors que l’index est l’aspect physique. Par conséquent, la contrainte unique est plus déclarative. Je préférerais une contrainte unique dans presque tous les cas.

Dmitry Frenkel
la source
8
-1 Dans SQL Server, ce qui suit est incorrect: "une contrainte de clé étrangère sur une autre table peut référencer des colonnes qui constituent une contrainte unique. Ceci n'est pas vrai pour les index uniques". Dans SQL Server, nous pouvons faire référence aux contraintes FK pour des index uniques.
AK
4
La possibilité pour une contrainte de clé étrangère de référencer un index unique a été, je pense, ajoutée à SQL Server 2005. De nombreuses sources, y compris certaines pages de BOL, n'ont pas été mises à jour pour refléter les modifications. Je ne pense donc pas que la réponse de Dmitry mérite les votes négatifs. Le reste de sa réponse est sans équivoque: les contraintes sont conformes à la norme ANSI, pas les index.
Greenstone Walker
malgré ces votes négatifs, ma réponse préférée.
miracle173
Les normes sont importantes. Si les normes Ansi consistent à utiliser une contrainte unique, nous devons utiliser une contrainte unique.
Rhyous
1

Dans Oracle, une différence majeure est que vous pouvez créer un index unique par fonction, ce qui n'est pas réalisable avec des contraintes uniques:

Par exemple

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

Donc, ce fk_xyzn’est unique que pour les disques qui ont amount != 0.

Amir Pashazadeh
la source
7
Dans SQL Server (balise de la question), les index peuvent être filtrés avec une WHEREclause. CREATE UNIQUE NONCLUSTERED INDEX P4_U ON DBO.P4 ( PID ) WHERE TXT = 'qwert' ;
Greenstone Walker
-3

La contrainte UNIQUE est préférable à l'index UNIQUE. Lorsque la contrainte n'est pas unique, vous devez utiliser un index standard ou non unique. La contrainte est également un autre type d'index. Index est utilisé pour un accès plus rapide.

Les index uniques peuvent avoir des clauses where. Par exemple, vous pouvez créer des index pour chaque année en fonction de la colonne de date.

WHERE Sale_Date BETWEEN '2012-01-01' AND '2012-12-31'
Ravi Ramaswamy
la source
C'est bien de voir où la clause avantage est mentionnée.
crokusek
3
"La contrainte est aussi un autre type d'index." Non ce n'est pas. Certaines contraintes (PK, UQ, FK) peuvent être et sont souvent appliquées par l’utilisation d’index. Pas nécessairement si et pas par défaut dans tous les SGBD.
Ypercubeᵀᴹ