Estoy desarrollando una base de datos SQL Server 2012 y tengo dudas sobre las columnas nvarchar como claves principales.
Tengo esta tabla:
CREATE TABLE [dbo].[CODES]
(
[ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[FLAG] [tinyint] NOT NULL,
[IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE_LEVEL] ASC,
[CODE] ASC
)
)
Pero ahora quiero usar la [CODE]
columna como clave principal y eliminar la [ID_CODE]
columna.
¿Hay algún problema o penalidad si tengo una NVARCHAR
columna como PRIMARY KEY
?
[CODE]
El valor de la columna debe ser único, por lo que he pensado que puedo establecer una UNIQUE
restricción para esa columna.
¿Tengo que usar [CODE]
como clave principal o es mejor si establezco una UNIQUE
restricción en la [CODE]
columna?
sql-server
primary-key
unique-constraint
VansFannel
fuente
fuente
CODE
columna debe ser única, pero no una Clave principal. Sospecho que lleva información. Si esa información es de alguna manera modificable, entoncesCODE
debería cambiar o estar desactualizado. Eso haría que su Clave primaria sea volátil, y no puedo ver que termine bien. Lo mejor es dejar que su PK sea solo una clave, y su CÓDIGO puede hacer lo que quiera. Solo una opinión.Respuestas:
Sí, absolutamente hay consecuencias negativas por usar una cadena en lugar de un tipo numérico para una Clave primaria, y aún más si esa PK está agrupada (que en realidad es en su caso). Sin embargo, el grado en el que ve el (los) efecto (s) del uso de un campo de cadena es una función de a) cuántas filas hay en esta tabla, yb) cuántas filas en otras tablas tienen Clave externa para esta PK. Si solo tiene 10k filas en esta tabla y 100k filas en algunas otras tablas que FK a esta tabla a través de ese campo, entonces tal vez no sea tan notable. Pero esos efectos ciertamente se vuelven más notorios a medida que aumenta el recuento de filas.
Debe tener en cuenta que los campos en un índice agrupado se transfieren a índices no agrupados. Entonces, no solo está mirando hasta 40 bytes por fila, sino (40 * algún_número) bytes. Y en cualquier tabla FK que tenga esos mismos 40 bytes en la fila, más a menudo habrá un índice no agrupado en ese campo, ya que se está utilizando en JOIN, por lo que ahora se duplica en cualquier tabla que FK éste. Si uno se inclina a pensar que 40 bytes * 1 millón de filas * 10 copias no son motivo de preocupación, consulte mi artículo ¡El disco es barato! ORLY? que detalla todas (o al menos la mayoría) de las áreas afectadas por esta decisión.
La otra cosa a tener en cuenta es que filtrar y ordenar cadenas, especialmente cuando no se utiliza una intercalación binaria (supongo que está utilizando la base de datos predeterminada que generalmente no distingue entre mayúsculas y minúsculas) es mucho menos eficiente (es decir, lleva más tiempo) que cuando se usa
INT
/BIGINT
. Esto afecta a todas las consultas que filtran / unen / clasifican en este campo.Por lo tanto, usar algo así
CHAR(5)
probablemente estaría bien para una PK agrupada, pero principalmente si también se definió conCOLLATE Latin1_General_100_BIN2
(o algo así).¿Y puede
[CODE]
cambiar el valor de alguna vez? En caso afirmativo, esa es una razón aún más para no usarlo como PK (incluso si configura los FK enON UPDATE CASCADE
). Si no puede o no cambiará, eso está bien, pero todavía hay razones más que suficientes para no usarlo como una PK en clúster.Por supuesto, la pregunta podría estar formulada incorrectamente, ya que parece que actualmente ya tiene este campo en su PK.
De todos modos, su mejor opción, con mucho, es usarlo
[ID_CODE]
como PK en clúster, usar ese campo en tablas relacionadas como FK y mantenerlo[CODE]
como unUNIQUE INDEX
(lo que significa que es una "clave alternativa").Actualización
Un poco más de información basada en esta pregunta en un comentario sobre esta respuesta:
Todo esto depende de muchos factores, algunos de los cuales ya he mencionado pero que reafirmaré:
Una clave primaria es cómo se identifica la fila individual, independientemente de si se hace referencia a ella por cualquier clave externa. La forma en que su sistema identifica internamente la fila está relacionada, pero no necesariamente con la forma en que sus usuarios se identifican / esa fila. Cualquier columna NOT NULL con datos únicos podría funcionar, pero hay cuestiones prácticas a considerar, especialmente si la PK es, de hecho, referenciada por alguna FK. Por ejemplo, los GUID son únicos y algunas personas realmente les gusta usarlos por varias razones, pero son bastante malos para los índices agrupados (
NEWSEQUENTIALID
es mejor, pero no perfecto). Por otro lado, los GUID están bien como teclas alternativas y la aplicación los usa para buscar la fila, pero las UNIONES todavía se hacen usando una PK INT (o similar).Hasta ahora no nos ha dicho cómo se
[CODE]
ajusta el campo en el sistema desde todos los ángulos, aparte de ahora mencionar que así es como se buscan las filas, pero ¿es eso para todas las consultas o solo algunas? Por lo tanto:En cuanto al
[CODE]
valor:Con respecto a esta tabla:
[CODE]
o[ID_CODE]
) en otras tablas, incluso si no están explícitamente con clave externa?[CODE]
es el único campo utilizado para obtener filas individuales, ¿para qué sirve el[ID_CODE]
campo? Si no se usa, ¿por qué tenerlo en primer lugar (que podría depender de la respuesta a "¿Puede[CODE]
cambiar alguna vez el campo?")?Esta decisión no puede tomarse únicamente con la pregunta "¿NVARCHAR sí o no?". Una vez más, diré que, en términos generales, no me parece una buena idea, pero ciertamente hay momentos en que está bien. Dado que hay tan pocos campos en esta tabla, no es probable que haya más, o al menos no muchos, índices. Por lo tanto, puede estar bien de cualquier manera para tener
[CODE]
como Índice agrupado. Y si ninguna otra tabla hace referencia a esta tabla, entonces también podría estar bien convirtiéndola en PK. Pero, si otras tablas hacen referencia a esta tabla, optaría por el[ID_CODE]
campo como PK, incluso si no está agrupado.fuente
[ID_CODE]
, comoPRIMARY KEY
, la mejor opción si uso la[CODE]
columna para buscar la tabla?Tienes que separar los conceptos:
La clave primaria es un concepto de diseño , una propiedad lógica de las entradas de la tabla. Debe ser inmutable durante la vida útil de la entrada de la tabla y debe ser la clave utilizada en la aplicación para hacer referencia a la entrada.
El índice agrupado es un concepto de almacenamiento , una propiedad física. Debe ser la ruta de acceso más común para las consultas, debe servir para satisfacer el índice de cobertura en la mayoría de los casos y satisfacer la mayor cantidad posible de consultas de rango.
No es necesario que la clave primaria sea el índice agrupado. Puede tener
ID_CODE
como PK y(CODE_LEVEL, CODE)
como clave agrupada. O al revés.Una clave agrupada más grande tiene algunas repercusiones negativas, ya que la clave más amplia significa menor densidad en las páginas de índice y un mayor tamaño consumido en todos los índices no agrupados. ya se han derramado toneladas de tinta sobre este tema, por ejemplo. comience desde Más consideraciones para la clave de agrupamiento: ¡el debate del índice agrupado continúa! .
Pero la esencia del asunto es que la elección de la clave de índice agrupada es principalmente una compensación. Por un lado, tiene requisitos de tamaño de almacenamiento, con repercusiones generales en el rendimiento (clave más grande -> tamaño más grande -> más IO, y el ancho de banda de IO es probablemente el recurso más escaso que tiene). Por otro lado, elegir la clave agrupada incorrecta en nombre del ahorro de espacio puede tener consecuencias en el rendimiento de las consultas, a menudo peores que los problemas derivados de una clave amplia.
En cuanto a la elección de la clave principal, ni siquiera debería ser un problema: su modelo de datos, la lógica de su aplicación, debe dictar cuál es la clave principal.
Dicho esto, mi 2c: no
NVARCHAR(20)
es ancho. Es un tamaño de clave en clúster perfectamente aceptable, incluso para una tabla grande.fuente
[ID_CODE]
, comoPRIMARY KEY
, la mejor opción si uso la[CODE]
columna (y tal vez[CODE_LEVEL]
) para buscar la tabla?[CODE]
la columna como clave principal.Nunca permitiría que nadie haga
nvarchar(20)
un PK en mi base de datos. Pierdes espacio en disco y memoria caché. Todos los índices de esta tabla y todos los FKs replican este amplio valor. Tal vez un char (20) si pueden justificarlo. ¿En qué tipo de datos está tratando de almacenarCODE
? ¿Realmente necesitas almacenar caracteres nvarchar? Tiendo a hacer valores PK "internos" no vistos por los usuarios, y trato de mantener los valores que se muestran por separado. Los valores mostrados a veces necesitan ser cambiados, lo que se vuelve muy problemático con PKs + FKs.Además, ¿se da cuenta de que una 'identidad bigint (1,1)' puede aumentar hasta 9.223.372.036.854.775.807?
A menos que esté construyendo esta base de datos para Google, ¿no será suficiente una normalidad
int identity (1,1)
con un límite superior a los 2 mil millones?fuente
[ID_CODE]
, comoPRIMARY KEY
, la mejor opción si uso la[CODE]
columna para buscar la tabla? Gracias.No debe haber una penalización inherente / notable que no sea el riesgo de usar teclas anchas cuando se usa nvarchar / varchar si no está al tanto. Especialmente si comienzas a combinarlos en teclas compuestas.
Pero en tu ejemplo de una longitud (20) deberías estar bien y no me preocuparía mucho por eso. Porque si el CÓDIGO es cómo consulta principalmente sus datos, un índice agrupado que suena muy sensato.
Sin embargo, debe considerar si realmente lo quiere como clave principal o simplemente como un índice único (agrupado). Hay una (pequeña) diferencia entre el índice agrupado y la clave primaria (básicamente, la clave primaria identifica sus datos, pero el índice es cómo consulta los datos), por lo que si lo desea, podría hacer su ID_Code tan fácilmente como una clave primaria y crea un índice agrupado único sobre CODE. (aviso: SQL Server convertirá automáticamente su clave principal en un índice agrupado, a menos que usted mismo haya creado manualmente el índice agrupado)
También considere si realmente necesita ID_Code ahora que tiene un CÓDIGO único.
fuente
NVARCHAR(20)
tiene un tamaño de 40 bytes (máximo), y dado que es una columna de longitud variable , no es realmente la mejor opción para un índice agrupado.ID_CODE
ser unBIGINT IDENTITY
sería la mejor opción aquí!