¿Por qué el uso de teclas de cadena generalmente se considera una mala idea?

24

Esto me ha estado molestando por un tiempo. La mayoría de las veces, cuando se trata de almacenar datos en estructuras como tablas hash, programadores, libros y artículos, insisten en que indexar elementos en dichas estructuras por valores de String se considera una mala práctica. Sin embargo, hasta ahora, no he encontrado una sola fuente para explicar también POR QUÉ se considera una mala práctica. ¿Depende del lenguaje de programación? En el marco subyacente? En la implementación?

Tome dos ejemplos simples, si ayuda:

Una tabla de tipo SQL donde las filas son indexadas por una clave primaria de cadena.

Un diccionario .NET donde las claves son cadenas.


fuente
99
Tener claves de cadena no es una mala idea en general. Sospecho que esas declaraciones se hicieron en un contexto donde hay un mejor tipo de clave disponible. Tengo diccionarios .net con teclas de cadena todo el tiempo. ¿Puedes dar algunos ejemplos de esta afirmación?
CodesInChaos
3
Por lo general, desea claves principales que no cambien durante la vida útil de un objeto / fila. Entonces, por ejemplo, usernamecomo la clave principal de una userstabla probablemente no sea la mejor idea, y preferiría una identificación de incremento automático. Pero eso usernamees una cadena solo es incidental, ser una propiedad mutable es el problema principal
CodesInChaos
En una base de datos, considere cómo indexaría las cadenas en lugar de los enteros.
@CodesInChaos Ojalá pudiera recordar dónde encontré la mayoría de los casos, pero por ahora puedo pegar la parte que me recordó el problema. Fue de una presentación de diapositivas de GDC de Valve que discutió los diálogos del juego y almacenó hechos sobre el mundo en pares <clave = cadena, valor = objeto>.
2
Las cuerdas están bien. Simplemente no cadenas 'mágicas'. Entonces, cuando use una tabla hash, asegúrese de no tener cadenas desnudas en su código. Debe evitar los valores de texto grandes como claves porque no funcionan bien, pero en la mayoría de las situaciones del mundo real, una cadena de texto corta es tan rápida como un entero (no son bases de datos masivas). También puede usar teclas alternativas, por ejemplo, la clave primaria es un número, pero también hay un 'slug' o una cadena única que también es única.
ipaul

Respuestas:

17

Todo tiene que ver básicamente con las dos cosas:

1) La velocidad de búsqueda (donde a los enteros, por ejemplo, les va mucho mejor)

2) El tamaño de los índices (donde los índices de cadena explotarían)

Ahora todo depende de sus necesidades y del tamaño del conjunto de datos. Si una tabla o una colección tiene como 10-20 elementos, el tipo de clave es irrelevante. Será muy rápido incluso con una tecla de cadena.

PD: Puede que no esté relacionado con su pregunta, pero las guías también se consideran malas para las claves de la base de datos (16 bytes Guid vs. 4 bytes entero). En grandes volúmenes de datos, las guías ralentizan la búsqueda.

conejito
fuente
No siempre: los GUID incrementales son posibles. Los índices seguirán siendo más grandes, pero la penalización de búsqueda no será tan mala.
Sam
77
En realidad están bien. Debe observar la relación entre el tiempo de E / S del disco de tiempo y la comparación de valores en la memoria. Dado que los tiempos de acceso al disco abruman la comparación de memoria, lo único que realmente importa al analizar el rendimiento de la base de datos es IO. Si la clave es un GUID, una cadena o un número entero no es realmente crítico. El tamaño del índice afecta cuántos valores de índice caben en una página, pero si la clave es un int 4 bytes (que puede no ser lo suficientemente grande y no puede ser generado por el cliente) o un valor de 16 bytes no es una preocupación importante. En algunas bases de datos, los rowId pueden tener un tamaño de 16 bytes.
ipaul
9

Hay un problema más con el uso de cadenas como claves, o más exactamente, el uso de literales de cadena como claves, dejando de lado las razones de rendimiento / eficiencia. Errores tipográficos Si usa literales de cadena como claves en un diccionario, se está preparando para una desagradable sorpresa cuando uno se "ReceiverId"convierte en a "RecieverId". Configure constantes para almacenar los valores clave y reutilícelos cada vez que acceda al diccionario.

Trivial y obvio, se puede decir, sin embargo, una cantidad asombrosa de ejemplos de código .NET en la web usa literales de cadena, propagando esta práctica dudosa. ASP.NET con todas las Sesiones, ViewStates y QueryParams esparcidos por la base de código es particularmente culpable aquí.

scrwtp
fuente
No es trivial en mi humilde opinión. También he visto casos en los que hay claves "1"y "1 "en la misma tabla.
pswg
Se vuelve aún más divertido cuando agregas mayúsculas y minúsculas en la mezcla también. Visto un montón de personas, incluyéndome a mí, tropiezo directamente con eso.
Tony Hopkinson
Incluso mejor que usar constantes, al menos en C #, es usar Expresiones en su lugar. De esa manera puede generar sus cadenas a partir de los nombres de métodos / propiedades, etc., de modo que sus búsquedas de cadenas se vuelvan seguras y fáciles de refactorizar.
GoatInTheMachine
4

Hay muchas compensaciones aquí. En realidad, uso claves de cadena con frecuencia, pero a menudo incluyo claves secundarias sustitutas para las uniones (obviamente, sería al revés si estuviera usando MySQL). Sin embargo, hay casos en los que no.

Primero, soy un fanático de declarar las claves naturales como la clave principal donde la base de datos puede manejar esto bien (PostgreSQL, por ejemplo). Esto ayuda con la normalización y permite un diseño de base de datos más claro. Las claves sustitutas facilitan la unión.

Hay dos razones por las que generalmente agrego claves sustitutas:

  1. No siempre está claro qué es una clave natural. A veces estos tienen que ser cambiados. Cambiar una clave compuesta natural cuando se usa para uniones e integridad referencial es complicado y propenso a errores.

  2. Unir el rendimiento en las teclas compuestas es problemático y una vez que sigue la ruta de la clave natural, se queda atascado allí.

Sin embargo, en los casos en que una clave natural es de definición, de columna única y de texto, generalmente me uno a la clave de cadena. Mi razón para hacerlo es que esto a menudo evita las uniones en la búsqueda. El uso más común es proporcionar un diseño de base de datos adecuado alrededor del caso de uso de los tipos de enumeración. En la mayoría de los casos, estos no requieren la combinación adicional para consultas de rutina. Entonces, donde este es el caso, las teclas de cadena como teclas de combinación tienen mucho sentido.

Por ejemplo, en LedgerSMB, almacenamos categorizaciones de cuentas. Estos se identifican por referencia de cadena. Y algunos otros datos se almacenan con la referencia de cadena que se utiliza para aplicar reglas con respecto a las combinaciones de categorizaciones que pueden afectar a una cuenta. El único momento en que se necesita la lógica es al guardar un conjunto de categorizaciones, por lo que nos unimos en la tecla de cadena.

En cuanto a por qué el valor predeterminado sería teclas enteras, no creo que sea solo una cuestión de tamaño de índice. Un gran problema es la gestión de claves. Dado que la clave es arbitraria y puede estar tratando con millones de registros, debe tener una forma de generar cadenas únicas. Hay casos en los que las personas usan UUID para esto, pero hay una probabilidad distinta de cero de colisión de UUID, y donde se almacenan miles de millones de registros, esta posibilidad se vuelve lo suficientemente alta como para que la posibilidad de colisión con tipos enteros incrementales sea cero por definición.

Chris Travers
fuente
No es distinto de cero si logra hacer que el tipo entero vuelva a cero. Para un tipo sin firmar de 32 bits, eso está a solo 4G de distancia, lo cual es inquietantemente cercano con "miles de millones de registros" ...
Donal Fellows
Si tiene una base de datos que puede decir "error en lugar de envolver" es cero. En cualquier caso, es más fácil gestionar la posibilidad de colisión con enteros incrementales que con valores pseudoaleatorios.
Chris Travers
1

Hay una serie de posibles problemas con el uso de cadenas como claves, especialmente cuando se trata de tablas tipo sql. Como mencionó @bunny, los índices para sus tablas serán más grandes, pero creo que de manera más significativa, cualquier relación de clave externa con la tabla involucrará AMBAS tablas para contener la cadena en lugar de un identificador de peso más ligero (entero) . Si encuentra que hay incluso más tablas con referencias a la primera, las claves de cadena proliferarán en su base de datos.

Matthew Flynn
fuente
1

No es una mala idea en sí misma, por lo general, con una perspectiva de 20/20, un compromiso de diseño deficiente. La flexibilidad y el rango de la cadena frente al costo y la complejidad adicionales.

Si el entero hace el rango de trabajo sabio y la mayor parte del costoso procesamiento no necesita saber qué representa el entero, use uno.

Tony Hopkinson
fuente
0

De alguna manera recuperó los datos incorrectos de una tabla hash.

¿Quiso decir "DaytimeTelephone" o "EveningTelephone"?

o

¿Querías decir 1234567 o 1234576?

Si bien los números son posiblemente más eficientes para la máquina , cada vez que las cosas salen mal (y lo hacen), corresponde a usted y a mí dar sentido a lo que sucedió y, en ese momento, ese ahorro de unos pocos bytes de almacenamiento y unos pocos micro (nano?) - segundos de procesamiento pierden claridad cada vez.

Phill W.
fuente
1
Y así terminas con una lista de constantes, usando el nombre de la constante en tu código para representar el número mágico ... Java enumera al rescate para abstraerlo aún más y dejándote solo el nombre y el ordinal mapeo invisible.
partir
-1

Muchas compensaciones y ninguna respuesta correcta. Muchos programadores nunca considerarían el uso de claves de cadena en la base de datos porque no conocen el hash y cómo funciona una base de datos. Las teclas de cadena siempre que sean extremadamente estables o sin sentido (sustitutos), son una buena opción de diseño en muchas circunstancias.

musgo23
fuente
2
Esta respuesta no agrega nada que no se haya dicho en las otras respuestas, que lo dicen mejor.
Martijn Pieters
-2

la clave de cadena tendrá sentido cuando se trata de una tabla de búsqueda con aproximadamente 10-100 registros de cadena corta; los datos relacionados son más legibles + por ejemplo, seguimiento de cambios (identificación numérica / guid vs. cadena, por ejemplo, "Administrador"); Por cierto, la base de datos de membresía ASP.NET utiliza claves de cadena para AspNetRoles.

Alfred Hitchcock
fuente