¿Cuándo debo usar una restricción única en lugar de un índice único?

195

Cuando quiero que una columna tenga valores distintos, puedo usar una restricción

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

o puedo usar un índice único

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

create unique index I_t2 on t2(code);

Las columnas con restricciones únicas parecen ser buenas candidatas para índices únicos.

¿Hay alguna razón conocida para usar restricciones únicas y no usar índices únicos en su lugar?

bernd_k
fuente
99
¿son realmente diferentes? Creo que en algunas bases de datos, por ejemplo, postgresql, una restricción única simplemente crea un índice único. No respondo porque no sé nada sobre el servidor SQL.
xenoterracide
66
en postgresql, puede usar una expresión en un índice único pero no en una restricción única.
Neil McGuigan
1
En MS SQL, se implementan igual. Intente crear dos tablas con los mismos datos, una con una restricción única y la otra con un índice único. Usarán la misma cantidad de espacio de índice, y ambos podrán buscar contra el índice único que (en la práctica) se crea de cualquier manera.
Jon of All Trades

Respuestas:

153

Bajo el capó se implementa una restricción única de la misma manera que un índice único: se necesita un índice para cumplir de manera eficiente el requisito de hacer cumplir la restricción. Incluso si el índice se crea como resultado de una restricción ÚNICA, el planificador de consultas puede usarlo como cualquier otro índice si lo ve como la mejor manera de abordar una consulta determinada.

Por lo tanto, para una base de datos que admite ambas características, la elección de cuál usar se reducirá a menudo al estilo y la consistencia preferidos.

Si planea usar el índice como un índice (es decir, su código puede depender de la búsqueda / clasificación / filtrado en ese campo para ser rápido), usaría explícitamente un índice único (y comentaría la fuente) en lugar de una restricción para hacer eso claro: de esta manera, si el requisito de unicidad se cambia en una revisión posterior de la aplicación, usted (u otro codificador) sabrá para asegurarse de que se coloca un índice no único en lugar del único (solo eliminar una restricción única eliminaría el índice por completo). También se puede nombrar un índice específico en una pista de índice (es decir, WITH (INDEX (ix_index_name)), que no creo que sea el caso del índice creado detrás de escena para gestionar la unicidad, ya que es poco probable que sepas su nombre.

Del mismo modo, si solo necesita imponer la unicidad como una regla de negocio en lugar de que el campo deba buscarse o usarse para ordenar, entonces usaría la restricción, nuevamente para hacer que el uso previsto sea más obvio cuando alguien más mira la definición de su tabla.

Tenga en cuenta que si usa una restricción única y un índice único en el mismo campo, la base de datos no será lo suficientemente brillante como para ver la duplicación, por lo que terminará con dos índices que consumirán espacio adicional y ralentizarán las inserciones / actualizaciones de fila.

David Spillett
fuente
1
Me pregunto acerca de "la base de datos no será lo suficientemente brillante"? ¿Es eso cierto para todos los RDBMS? ¿Es obligatorio por el estándar SQL? E incluso si es así (y me pregunto por qué debería serlo), ¿todas las implementaciones lo implementan de esa manera? O: ¿por qué un DB no puede ser lo suficientemente "brillante"?
Jürgen A. Erhard
44
@jae: un DBMS ciertamente podría ser lo suficientemente brillante, pero tendría que verificar con cada DBMS para ver si lo es. Si le pide a MSSQL que cree dos índices idénticos, creará dos en lugar de uno mencionado por dos nombres (al menos este fue el caso la última vez que vi una situación como esa (debido a un error de copiar + pegar de mi parte)), así que supongo que es el caso si uno de los índices está presente debido a una restricción.
David Spillett
3
+1 @David Spillett Creo que básicamente el DBMS simplemente supone que sabes lo que estás haciendo; Si tiene ganas de crear el mismo índice dos veces, no lo cuestiona al respecto.
Andrew Barber
2
muy perspicaz. ¿Sabes si este comportamiento también está en MySQL y Apache Derby?
corsiKa
55
Usted puede nombrar a una restricción y utilizarlo en una sugerencia de índice. CREATE TABLE #T(X INT CONSTRAINT PK PRIMARY KEY NONCLUSTERED);SELECT * FROM #T WITH(INDEX(PK)) WHERE X = 1. Sin embargo, los índices pueden ser más flexibles porque las restricciones no admiten todas las opciones de índice, como INCLUDEcolumnas d o índices filtrados.
Martin Smith
101

Además de los puntos en otras respuestas, aquí hay algunas diferencias clave entre los dos.

Nota: Los mensajes de error son de SQL Server 2012.

Errores

La violación de una restricción única devuelve el error 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 violación de un índice único devuelve el error 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.

Deshabilitar

Una restricción única no se puede deshabilitar.

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.

Pero el índice único detrás de una restricción de clave principal o una restricción única se puede deshabilitar, al igual que cualquier índice único. Hat-tip Brain2000.

ALTER INDEX P1_u ON dbo.P1 DISABLE ;

Tenga en cuenta la advertencia habitual de que deshabilitar un índice agrupado hace que los datos sean inaccesibles.

Opciones

Las restricciones únicas admiten opciones de indexación como FILLFACTORy IGNORE_DUP_KEY, aunque este no ha sido el caso para todas las versiones de SQL Server.

Columnas Incluidas

Los índices no agrupados pueden incluir columnas no indexadas (denominadas índice de cobertura, esta es una mejora importante del rendimiento). Los índices detrás de las restricciones PRIMARY KEY y UNIQUE no pueden incluir columnas. Punta de sombrero @ypercube.

Filtración

Una restricción Unique no se puede filtrar.

Se puede filtrar un índice único.

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

Restricciones de clave extranjera

Una restricción de clave externa no puede hacer referencia a un índice único filtrado, aunque puede hacer referencia a un índice único no filtrado (creo que esto se agregó en SQL Server 2005).

Nombrar

Al crear una restricción, especificar un nombre de restricción es opcional (para los cinco tipos de restricciones). Si no especifica un nombre, MSSQL generará uno para usted.

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

Al crear índices, debe especificar un nombre.

Punta de sombrero @ i-one.

Enlaces

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

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

Caminante de piedra verde
fuente
Se puede deshabilitar y habilitar una restricción única mediante el mismo método que un índice: ALTER INDEX tbl ON uconstraint DISABLE, ALTER INDEX tbl ON uconstraint REBUILD
Brain2000
Gracias @ Brain2000. Casualmente, enseñé una sección sobre índices de desactivación esta mañana justo antes de leer este comentario.
Greenstone Walker
10

Para citar a MSDN como una fuente autorizada:

No hay diferencias significativas entre crear una restricción ÚNICA y crear un índice único que sea independiente de una restricción . La validación de datos ocurre de la misma manera, y el optimizador de consultas no diferencia entre un índice único creado por una restricción o creado manualmente. Sin embargo, la creación de una restricción ÚNICA en la columna deja claro el objetivo del índice ... más información aquí

Y...

El Motor de base de datos crea automáticamente un índice ÚNICO para aplicar el requisito de unicidad de la restricción ÚNICA. Por lo tanto, si se intenta insertar una fila duplicada, el Motor de base de datos devuelve un mensaje de error que indica que se ha violado la restricción ÚNICA y no agrega la fila a la tabla. A menos que se especifique explícitamente un índice agrupado, se crea un índice único no agrupado de forma predeterminada para aplicar la restricción ÚNICA ... más información aquí

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

usuario919426
fuente
6

Una de las principales diferencias entre una restricción única y un índice único es que una restricción de clave externa en otra tabla puede hacer referencia a columnas que conforman una restricción única. Esto no es cierto para los índices únicos. Además, las restricciones únicas se definen como parte del estándar ANSI, mientras que los índices no. Finalmente, se considera que la restricción única vive en el ámbito del diseño de bases de datos lógicas (que pueden ser implementadas de manera diferente por diferentes motores de base de datos) mientras que el índice es un aspecto físico. Por lo tanto, la restricción única es más declarativa. Prefiero una restricción única en casi todos los casos.

Dmitry Frenkel
fuente
8
-1 En SQL Server, lo siguiente es incorrecto: "una restricción de clave externa en otra tabla puede hacer referencia a columnas que constituyen una restricción única. Esto no es cierto para índices únicos". En SQL Server, podemos referir las restricciones FK a índices únicos.
AK
44
Creo que la capacidad de una restricción de clave externa para hacer referencia a un índice único se agregó en SQL Server 2005. Muchas fuentes, incluidas algunas páginas en BOL, no se han actualizado para reflejar los cambios, por lo que no creo que la respuesta de Dmitry merece los votos negativos. El resto de su respuesta es acertada: las restricciones son estándar ANSI, los índices no.
Greenstone Walker
a pesar de estos votos negativos mi respuesta favorita.
miracle173
Las normas son importantes. Si los estándares Ansi van a usar una restricción única, entonces deberíamos usar una restricción única.
Rhyous
1

En Oracle, una diferencia importante es que puede crear un índice de función única, que no es factible con restricciones únicas:

Por ejemplo

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

Por fk_xyzlo tanto, es único para el registro que tienen amount != 0.

Amir Pashazadeh
fuente
77
En SQL Server (la etiqueta de la pregunta), los índices se pueden filtrar con una WHEREcláusula. CREATE UNIQUE NONCLUSTERED INDEX P4_U ON DBO.P4 ( PID ) WHERE TXT = 'qwert' ;
Greenstone Walker
-3

Se prefiere la restricción ÚNICA sobre el índice ÚNICO. Cuando la restricción no es única, debe usar un índice regular o no único. La restricción también es otro tipo de índice. El índice se usa para un acceso más rápido.

Los índices únicos pueden tener cláusulas where. Por ejemplo, puede crear índices para cada año en función de la columna de fecha

WHERE Sale_Date BETWEEN '2012-01-01' AND '2012-12-31'
Ravi Ramaswamy
fuente
Es bueno ver el beneficio de la cláusula where mencionado.
crokusek
3
"La restricción también es otro tipo de índice". No lo es. Algunas restricciones (PK, UQ, FK) pueden y a menudo se aplican mediante el uso de índices. Sin embargo, no necesariamente y no por defecto en todos los DBMS.
ypercubeᵀᴹ