Cadenas como claves primarias en la base de datos SQL

178

No estoy muy familiarizado con las bases de datos y las teorías detrás de cómo funcionan. ¿Es más lento desde el punto de vista del rendimiento (insertar / actualizar / consultar) usar cadenas para claves primarias que enteros?

cuerdas principales
fuente

Respuestas:

191

Técnicamente sí, pero si una cadena tiene sentido para ser la clave principal, entonces probablemente debería usarla. Todo esto depende del tamaño de la tabla para la que está haciendo y de la longitud de la cadena que será la clave principal (cadenas más largas == más difíciles de comparar). No necesariamente usaría una cadena para una tabla que tiene millones de filas, pero la cantidad de desaceleración de rendimiento que obtendrá al usar una cadena en tablas más pequeñas será minúscula para los dolores de cabeza que puede tener al tener un número entero que no No significa nada en relación con los datos.

kemiller2002
fuente
11
¿no dependería de la base de datos? ¿Pensaría que una cadena indexada correctamente no sería mucho más lenta si fuera de un número?
Ryan Guill
2
Estoy de acuerdo en que hay muchas variables a considerar. (En sqlserver), hemos visto problemas reales de rendimiento al usar cadenas con longitudes en la adolescencia media a alta y superiores, incluso cuando están indexadas. Compre que tiene razón, hay cosas para superar este hardware, por ejemplo.
kemiller2002
1
Lo suficientemente justo. Sin embargo, estaría de acuerdo en que si una cadena tiene sentido, eso es lo que debe usar. También diría que definitivamente hay momentos para los campos GUID o UUID en bases de datos donde un campo de autoincremento no funcionaría.
Ryan Guill
77
También tenga en cuenta que a menudo hay una gran diferencia entre un CHAR y un VARCHAR cuando se realizan comparaciones de índices
Tom H
77
El número de comentarios de esta respuesta deja en claro cuán incompleto es. Mencionar la indexación habría sido la respuesta mínima aceptable.
Pedro Rolo
74

Otro problema con el uso de cadenas como clave principal es que debido a que el índice se coloca constantemente en orden secuencial, cuando se crea una nueva clave que estaría en el medio del orden, el índice debe volver a secuenciarse ... si usa un auto número entero, la nueva clave se acaba de agregar al final del índice.

Jeff Martin
fuente
2
Sin embargo, esto puede causar "puntos calientes" para nuevos insertos. Siempre y cuando esté administrando su base de datos correctamente, debe tener espacio adicional en sus páginas para inserciones de todos modos y las divisiones de página deben ser raras.
Tom H
20
es entonces cuando las claves primarias están agrupadas. también puedes crearlos sin agrupar.
Aprendizaje
Los XID están ordenados, lo que podría ayudar si solo usa cadenas
xid
22

Las inserciones en una tabla que tiene un índice agrupado donde la inserción ocurre en el medio de la secuencia NO hace que el índice se reescriba. No hace que las páginas que comprenden los datos se reescriban. Si hay espacio en la página donde irá la fila, entonces se coloca en esa página. La página individual se reformateará para colocar la fila en el lugar correcto de la página. Cuando la página está llena, ocurrirá una división de página, con la mitad de las filas de la página yendo a una página y la otra mitad yendo a la otra. Las páginas se vuelven a vincular en la lista vinculada de páginas que comprenden una tabla de datos que tiene el índice agrupado. Como máximo, terminarás escribiendo 2 páginas de base de datos.

Mark Thompson
fuente
Buena explicación. ¿Pero esto es cierto para todas las bases de datos SQL? He oído hablar de problemas de rendimiento de MySQL al usar UUID aleatorio como clave principal.
hgoebl
13

Las cadenas son más lentas en las uniones y en la vida real rara vez son realmente únicas (incluso cuando se supone que deben ser). La única ventaja es que pueden reducir el número de uniones si se une a la tabla primaria solo para obtener el nombre. Sin embargo, las cadenas también están sujetas a cambios, lo que crea el problema de tener que arreglar todos los registros relacionados cuando cambia el nombre de la empresa o la persona se casa. Esto puede ser un gran impacto en el rendimiento y si todas las tablas que deberían estar relacionadas de alguna manera no están relacionadas (esto sucede con más frecuencia de lo que piensa), entonces también podría tener desajustes de datos. Un número entero que nunca cambiará durante la vida útil del registro es una opción mucho más segura desde el punto de vista de la integridad de los datos, así como desde el punto de vista del rendimiento. Las claves naturales generalmente no son tan buenas para el mantenimiento de los datos.

También quiero señalar que lo mejor de ambos mundos es a menudo usar una clave de autoincremento (o en algunos casos especializados, un GUID) como PK y luego poner un índice único en la clave natural. Obtiene las uniones más rápidas, no obtiene registros duplicados y no tiene que actualizar un millón de registros secundarios porque cambió el nombre de una empresa.

HLGEM
fuente
26
Las cadenas que son buenas candidatas para PK no tienen duplicados; de lo contrario, no serían buenas candidatas para PK. Piense en los códigos ICD-9, códigos de país, VIN #s. Usar un nombre como ejemplo de un problema con las claves naturales es erróneo, porque en primer lugar nunca deberían ser candidatos.
Tom H
66
@Tom H: los códigos del condado ISO cambian. [ en.wikipedia.org/wiki/ISO_3166-1#Editions_and_changes ] Como respuesta a una pregunta relacionada, dijo [ stackoverflow.com/questions/925266/… ] "Para PRIMARY KEY, asegúrese de que su singularidad esté bajo su control"
Steve Schnepp
44
@SteveSchnepp: sí, y el ISO es el organismo de confianza para gestionar ese cambio. Por otro lado, cuando necesita fusionar su secuencia monotónica de valores enteros incrementales con los de otra persona, está solo;)
cuando el
1
Estoy de acuerdo en que los nombres no deben considerarse como una clave, acabo de ver muchas veces cuando lo eran.
HLGEM
1
@onedaywhen fusionando 2 secuencias monótonas de incremento de enteros se hace fácilmente mediante prefijos o sufijos :)
Steve Schnepp
6

No importa lo que use como clave principal siempre que sea ÚNICO. Si le importa la velocidad o el buen diseño de la base de datos, use int a menos que planee replicar datos, luego use un GUID.

Si se trata de una base de datos de acceso o una pequeña aplicación, ¿a quién le importa realmente? Creo que la razón por la cual la mayoría de nosotros los desarrolladores damos una palmada al viejo int o guid en el frente es porque los proyectos tienen una forma de crecer en nosotros, y usted quiere dejarse la opción de crecer.

Al Katawazi
fuente
5

Demasiadas variables Depende del tamaño de la tabla, los índices, la naturaleza del dominio de clave de cadena ...

En general , los enteros serán más rápidos. ¿Pero será la diferencia lo suficientemente grande como para preocuparse? Es difícil de decir.

Además, ¿cuál es su motivación para elegir cuerdas? Las teclas numéricas de incremento automático a menudo también son mucho más fáciles . ¿Es semántica? ¿Conveniencia? Replicación / preocupaciones desconectadas? Su respuesta aquí podría limitar sus opciones. Esto también le recuerda una tercera opción "híbrida" que está olvidando: las guías.

Joel Coehoorn
fuente
eso no tiene sentido cloutierm, ¿qué quieres decir?
HLGEM
@HLGEM: Si entiendo que escriba, quiere decir como sincronizar registros creados en una computadora portátil con el db principal.
Joel Coehoorn
Quiero decir que tengo dos bases de datos separadas con las mismas entidades, solo una se actualiza con menos frecuencia para fines de almacenamiento persistente. Si la consulta para la entidad "California" en la base de datos A, que quiere que sea fundamentalmente el mismo "California" en la base de datos B.
mainstringargs
1
Y es 'como' sincronizar registros creados en una computadora portátil en el sentido de que es el mismo problema: los registros creados en un lugar no deben entrar en conflicto con los registros creados en otro. Una posible solución aquí son las claves Guid.
Joel Coehoorn
5

No se preocupe por el rendimiento hasta que tenga un diseño simple y sólido que esté de acuerdo con el tema que los datos describen y se ajusta bien con el uso previsto de los datos. Luego, si surgen problemas de rendimiento, puede resolverlos ajustando el sistema.

En este caso, casi siempre es mejor usar una cadena como clave primaria natural, siempre que pueda confiar en ella. No se preocupe si es una cadena, siempre que la cadena sea razonablemente corta, digamos unos 25 caracteres como máximo. No pagará un gran precio en términos de rendimiento.

¿Las personas de entrada de datos o las fuentes de datos automáticas siempre proporcionan un valor para la supuesta clave natural, o a veces se omite? ¿Ocasionalmente está mal en los datos de entrada? Si es así, ¿cómo se detectan y corrigen los errores?

¿Los programadores y los usuarios interactivos que especifican consultas pueden usar la clave natural para obtener lo que desean?

Si no puede confiar en la clave natural, invente un sustituto. Si inventa un sustituto, también podría inventar un número entero. Luego debe preocuparse por si ocultar el sustituto de la comunidad de usuarios. Algunos desarrolladores que no ocultaron la clave sustituta llegaron a lamentarlo.

Walter Mitty
fuente
3

Los índices implican muchas comparaciones.

Por lo general, las cadenas son más largas que los enteros y las reglas de intercalación pueden aplicarse para la comparación, por lo que comparar cadenas suele ser una tarea computacionalmente más intensa que comparar números enteros.

A veces, sin embargo, es más rápido usar una cadena como clave principal que hacer una unión adicional con una string to numerical idtabla.

Quassnoi
fuente
2

Sí, pero a menos que espere tener millones de filas, no usar una clave basada en cadenas porque es más lenta suele ser "optimización prematura". Después de todo, las cadenas se almacenan como números grandes, mientras que las teclas numéricas generalmente se almacenan como números más pequeños.

Sin embargo, una cosa a tener en cuenta es si tiene índices agrupados en cualquier tecla y está haciendo un gran número de inserciones que no son secuenciales en el índice. Cada línea escrita hará que el índice se vuelva a escribir. Si está haciendo inserciones por lotes, esto realmente puede ralentizar el proceso.

Sí, ese Jake.
fuente
2

Dos razones para usar enteros para columnas PK:

  1. Podemos establecer la identidad para el campo entero que se incrementó automáticamente.

  2. Cuando creamos PK, la base de datos crea un índice (Cluster o Non Cluster) que clasifica los datos antes de almacenarlos en la tabla. Al usar una identidad en una PK, el optimizador no necesita verificar el orden antes de guardar un registro. Esto mejora el rendimiento en mesas grandes.

Jatinder Singh
fuente
1

¿Cuál es su razón para tener una cadena como clave principal?

Simplemente establecería la clave primaria en un campo entero de incremento automático y pondría un índice en el campo de cadena.

De esa manera, si realiza búsquedas en la tabla, deberían ser relativamente rápidas, y todas sus uniones y búsquedas normales no se verán afectadas en su velocidad.

También puede controlar la cantidad del campo de cadena que se indexa. En otras palabras, puede decir "solo indexe los primeros 5 caracteres" si cree que será suficiente. O si sus datos pueden ser relativamente similares, puede indexar todo el campo.

John Bubriski
fuente
3
Creo que poner inteligencia en una clave es pedir problemas. ¿Se mantendrán únicos? ¿Comenzaron todos los números de cuenta con la abreviatura del estado al principio solo para la mudanza del cliente? Actualice un campo, no hay problema, todas esas tablas vinculadas por número de cuenta, qué desastre.
JeffO
1
Un ejemplo de uso de una cadena como PK podría ser una tabla de configuraciones. por ejemplo, settingNamePK, isUserEditable, isCustomerEditable, etc. Entonces, si desea modificar el comportamiento de configuración "ACTUALIZAR configuración SET ... DONDE settingNamePK = 'dailyWorkObligation'" es mucho más agradable que tener que usar ID y almacenar en algún lugar la asignación de ID. Por supuesto, podría tener un PK entero y tener el nombre de configuración como otra clave única también.
MeatPopsicle
Dado que la clave principal es un número entero con incremento automático, ¿no deberían las inserciones tampoco verse afectadas en su velocidad?
Dennis
Para los desarrolladores curiosos de Rails, aquí se explica cómo especificar una longitud de índice . Tenga en cuenta que SQLite no admite la longitud del índice.
Dennis
1

Desde el punto de vista del rendimiento: Sí, la cadena (PK) ralentizará el rendimiento en comparación con el rendimiento logrado utilizando un número entero (PK), donde PK ---> Clave primaria.

Desde el punto de vista de los requisitos: aunque esto no es parte de su pregunta, me gustaría mencionarlo. Cuando manejamos grandes cantidades de datos en diferentes tablas, generalmente buscamos el conjunto probable de claves que se pueden establecer para una tabla en particular. Esto se debe principalmente a que hay muchas tablas y, en su mayoría, cada una de ellas estaría relacionada entre sí a través de alguna relación (un concepto de clave externa). Por lo tanto, no siempre podemos elegir un número entero como Clave primaria, sino que elegimos una combinación de 3, 4 o 5 atributos como clave primaria para esas tablas. Y esas claves pueden usarse como una clave externa cuando relacionaríamos los registros con alguna otra tabla. Esto hace que sea útil relacionar los registros en diferentes tablas cuando sea necesario.

Por lo tanto, para un uso óptimo: siempre hacemos una combinación de 1 o 2 enteros con 1 o 2 atributos de cadena, pero nuevamente solo si es necesario.


fuente
0

Podría haber un gran malentendido relacionado con la cadena en la base de datos. Casi todos han pensado que la representación de números en la base de datos es más compacta que las cadenas. Piensan que en db-s los números se representan como en la memoria. Pero no es cierto. En la mayoría de los casos, la representación numérica está más cerca de una cadena como la representación como otra.

La velocidad de usar número o cadena depende más de la indexación que del tipo en sí.

takacsot
fuente
0

Por defecto, ASPNetUserIds son 128 cadenas de caracteres y el rendimiento está bien.

Si la clave TIENE que ser única en la tabla, debería ser la Clave. Este es el por qué;

clave de cadena primaria = relaciones correctas de base de datos, 1 clave de cadena (la primaria) y 1 índice de cadena (la primaria).

La otra opción es una Clave int típica, pero si la cadena TIENE que ser única, probablemente necesitará agregar un índice debido a consultas continuas para validar o verificar que es única.

Entonces, usar una clave de identidad int = Relaciones de base de datos incorrectas, 1 clave int (Primaria), 1 índice int (Primaria), Probablemente una cadena única Índice, y tener que validar manualmente la misma cadena no existe (algo así como una comprobación de sql )

Para obtener un mejor rendimiento usando un int sobre una cadena para la clave primaria, cuando la cadena TIENE que ser única, tendría que ser una situación muy extraña. Siempre he preferido usar teclas de cadena. Y como buena regla general, no desnormalice una base de datos hasta que NECESITA .

JPoole
fuente