¿Cuál puede ser la desventaja de tener siempre una sola columna entera como clave principal?


18

Dentro de una aplicación web en la que estoy trabajando, todas las operaciones de la base de datos se abstraen utilizando algunos repositorios genéricos definidos sobre Entity Framework ORM.

Sin embargo, para tener un diseño simple para los repositorios genéricos, todas las tablas involucradas deben definir un número entero único ( Int32en C #, inten SQL). Hasta ahora, este siempre ha sido el PK de la tabla y también el IDENTITY.

Las claves foráneas se usan mucho y hacen referencia a estas columnas enteras. Son necesarios tanto para la coherencia como para generar propiedades de navegación mediante el ORM.

La capa de aplicación generalmente realiza las siguientes operaciones:

  • carga de datos inicial de la tabla (*) -SELECT * FROM table
  • actualización -UPDATE table SET Col1 = Val1 WHERE Id = IdVal
  • eliminar -DELETE FROM table WHERE Id = IdVal
  • Insertar -INSERT INTO table (cols) VALUES (...)

Operaciones menos frecuentes:

  • Inserción masiva : BULK INSERT ... into tableseguida (*) de toda la carga de datos (para recuperar identificadores generados)
  • Eliminación masiva : esta es una operación de eliminación normal, pero "voluminosa" desde la perspectiva de ORM:DELETE FROM table where OtherThanIdCol = SomeValue
  • Actualización masiva : esta es una operación de actualización normal, pero "voluminosa" desde la perspectiva de ORM:UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue

* todas las tablas pequeñas se almacenan en caché a nivel de aplicación y casi todas SELECTsno llegarán a la base de datos. Un patrón típico es la carga inicial y muchos INSERTs, UPDATEsy DELETEs.

Según el uso actual de la aplicación, hay muy pocas posibilidades de alcanzar los 100 millones de registros en cualquiera de las tablas.

Pregunta: Desde la perspectiva de un DBA, ¿existen problemas importantes con los que pueda tener esta limitación de diseño de tabla?

[EDITAR]

Después de leer las respuestas (gracias por los excelentes comentarios) y los artículos de referencia, siento que tengo que agregar más detalles:

  1. Datos específicos de la aplicación actual : no mencioné la aplicación web actual, porque quiero entender si el modelo también se puede reutilizar para otras aplicaciones. Sin embargo, mi caso particular es una aplicación que extrae muchos metadatos de un DWH. Los datos de origen son bastante desordenados (desnormalizados de una manera extraña, con algunas inconsistencias, sin un identificador natural en muchos casos, etc.) y mi aplicación está generando entidades separadas y claras. Además, IDENTITYse muestran muchos de los identificadores generados ( ), para que el usuario pueda usarlos como claves comerciales. Esto, además de una refactorización masiva de código, excluye el uso de GUID .

  2. "No deberían ser la única forma de identificar de forma única una fila" (Aaron Bertrand ♦), es un muy buen consejo. Todas mis tablas también definen una RESTRICCIÓN ÚNICA para garantizar que no se permitan duplicados comerciales.

  3. Diseño dirigido por la aplicación front-end versus diseño dirigido por la base de datos : la elección del diseño es causada por estos factores

    1. Limitaciones de Entity Framework : se permiten PK de varias columnas, pero sus valores no se pueden actualizar

    2. Limitaciones personalizadas : tener una sola clave entera simplifica enormemente las estructuras de datos y el código que no es SQL. Por ejemplo: todas las listas de valores tienen una clave entera y valores mostrados. Más importante aún, garantiza que cualquier tabla marcada para el almacenamiento en caché podrá colocarse en un Unique int key -> valuemapa.

  4. Consultas de selección complejas : esto casi nunca sucederá porque todos los datos de tablas pequeñas (<20-30K registros) se almacenan en caché a nivel de aplicación. Esto hace la vida un poco más difícil al escribir el código de la aplicación (más difícil de escribir LINQ), pero la base de datos se ve mucho mejor:

    1. Vistas de lista : no generará SELECTconsultas en la carga (todo está en caché) o consultas que se vean así:

      SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)

      Todos los demás valores requeridos se obtienen mediante búsquedas en caché (O (1)), por lo que no se generarán consultas complejas.

    2. Editar vistas : generará SELECTdeclaraciones como esta:

      SELECT allcolumns FROM BigTable WHERE PKId = value1

(todos los filtros y valores son ints)


Puede encontrar estas publicaciones relevantes, ya que se analizan algunos aspectos lógicos, físicos y prácticos con respecto al uso de columnas con valores sustitutos generados por el sistema.
MDCCL

Respuestas:


19

Además de espacio en disco adicional (y, a su vez, uso de memoria y E / S), no hay ningún daño en agregar una columna IDENTIDAD incluso a las tablas que no necesitan una (un ejemplo de una tabla que no necesita una columna IDENTIDAD es una tabla de unión simple, como asignar un usuario a sus permisos).

Me abstengo de agregarlos ciegamente a cada tabla en una publicación de blog de 2010:

Pero las claves sustitutas tienen casos de uso válidos; solo tenga cuidado de no suponer que garantizan la unicidad (que a veces es la razón por la que se agregan), no deberían ser la única forma de identificar una fila de manera única. Si necesita utilizar un marco ORM, y su marco ORM requiere claves enteras de una sola columna, incluso en los casos en que su clave real no sea un entero, o no sea una sola columna, o ninguna, asegúrese de definir restricciones / índices únicos para tus llaves reales, también.


Gracias por la rápida respuesta. Sí, la aplicación usa un ORM (EF). No requiere teclas de columna de entero único, pero he introducido esta restricción para hacer que algunas operaciones genéricas sean mucho más fáciles (en cuanto al diseño). Además, todas las memorias caché de aplicaciones almacenan todo en mapas (diccionarios) para realizar recuperaciones rápidas por clave y la clave debe ser única. Como he elegido entradas en lugar de guías, me veo obligado a usar IDENTITY para cualquier tabla en la que inserte. Para tablas de valores fijos, no se requiere IDENTIDAD.
Alexei

Creo que existen algunos casos que requieren evitar la verificación de la unicidad en las claves naturales. Como alguien que trabaja con datos SIG, el que viene a la mente de inmediato es donde la clave natural es la geometría misma o la geometría más alguna clave foránea. Buscar cosas por una geometría exacta siempre será poco práctico, por lo que es poco probable que una restricción de singularidad ayude mucho y puede tener inconvenientes de rendimiento. Lo mismo podría ser cierto si parte de la clave natural es una columna de texto larga. Pero estoy de acuerdo: siempre que sea práctico, sí, se debe aplicar una restricción única sobre la clave natural.
jpmc26

13

Según mi experiencia, la razón principal y abrumadora para usar una identificación separada para cada tabla es la siguiente:

En casi todos los casos, mi cliente hizo un juramento de sangre en la fase de concepción de que algún campo externo "natural" XYZBLARGH_IDseguirá siendo único para siempre, y nunca cambiará para una entidad determinada, y nunca será reutilizado, eventualmente aparecieron casos donde el Las propiedades de la clave primaria se rompieron. Simplemente no funciona de esa manera.

Luego, desde el punto de vista del DBA, las cosas que hacen que un DB sea lento o hinchado ciertamente no son 4 bytes (o lo que sea) por fila, sino cosas como índices incorrectos o faltantes, reorganizaciones de tabla / índice olvidadas, parámetros de ajuste de RAM / espacio de tabla incorrectos , descuidando el uso de variables de enlace, etc. Esos pueden ralentizar el DB por factores de 10, 100, 10000 ... no una columna de ID adicional.

Entonces, incluso si hubiera una desventaja técnica y medible de tener 32 bits adicionales por fila, no se trata de si puede optimizar la identificación, sino si la identificación será esencial en algún momento, lo que será más Probable que no. Y no voy a contar todos los beneficios "blandos" de una posición de desarrollo de software (como su ejemplo ORM, o el hecho de que facilita a los desarrolladores de software cuando todas las ID por diseño tienen el mismo tipo de datos, etc.) .

NB: tenga en cuenta que no necesita una ID separada para n:mlas tablas de asociación porque para esas tablas las ID de las entidades asociadas deben formar una clave primaria. Un contraejemplo sería una n:masociación extraña que permite múltiples asociaciones entre las mismas dos entidades por cualquier razón extraña: esas necesitarían su propia columna de identificación para crear una PK. Sin embargo, hay bibliotecas ORM que no pueden manejar PK de varias columnas, por lo que sería una razón para ser indulgente con los desarrolladores, si tienen que trabajar con dicha biblioteca.


2
"extraña asociación n: m que permite múltiples asociaciones entre las mismas dos entidades" MUY común en la vida real. Por ejemplo, una persona posee un automóvil, luego los requisitos cambian para recuperarse cuando la propiedad comenzó y terminó, (una persona puede vender un automóvil y comprarlo más tarde, y bloquear su software ...)
Ian Ringrose

Sí, algo así, @IanRingrose.
AnoE

6

Si invariablemente agrega una columna adicional sin sentido a cada tabla y hace referencia solo a esas columnas como claves externas, entonces inevitablemente hará que la base de datos sea más compleja y difícil de usar. Efectivamente, eliminará los datos de interés para los usuarios de los atributos de clave externa y obligará al usuario / aplicación a hacer una unión adicional para recuperar esa misma información. Las consultas se vuelven más complejas, el trabajo del optimizador se vuelve más difícil y el rendimiento puede verse afectado.

Sus tablas estarán más escasamente pobladas con datos "reales" de lo que hubieran estado de otra manera. Por lo tanto, la base de datos será más difícil de comprender y verificar. También puede resultarle difícil o imposible aplicar ciertas restricciones útiles (donde las restricciones involucrarían múltiples atributos que ya no están en la misma tabla).

Te sugiero que elijas tus claves con más cuidado y las hagas enteras solo si tienes buenas razones para hacerlo. Base sus diseños de bases de datos en un buen análisis, integridad de datos, practicidad y resultados verificables en lugar de confiar en reglas dogmáticas.


1
Y, sin embargo, muchos sistemas tienen claves primarias de enteros sintéticos en cada tabla (por ejemplo, casi todas las aplicaciones de Ruby on Rails que se hayan escrito), sin sufrir tales problemas. Tampoco sufren el problema de tener que enviar cambios a las claves primarias (que se suponía que nunca debían suceder) en todas las tablas de claves externas.
David Aldridge

2
La pregunta pedía posibles desventajas, de ahí mi respuesta. No niego que las claves sustitutas pueden tener sentido si se usan con prudencia. Pero he visto tablas con 3,4,5 (o muchas más) claves foráneas sin sentido que, por lo tanto, requieren uniones de 3,4,5 o más para obtener resultados útiles de ellas. Un diseño más pragmático podría no requerir uniones en absoluto.
nvogel

1
No estoy convencido de que la ejecución de tales consultas sea el problema principal que las personas tienen con un diseño de este tipo; es la escritura de la consulta a la que a menudo se oponen.
David Aldridge

5

En mi experiencia con varias bases de datos, una clave primaria entera siempre es mejor que las aplicaciones que no tienen claves definidas. O que tienen claves que unen media docena de columnas varchar de formas incómodas que no son lógicas ... (suspiro)

He visto aplicaciones que cambiaron de PK enteros a GUID. Su razón para hacerlo fue porque era necesario fusionar datos de múltiples bases de datos de origen en ciertos casos. Los desarrolladores cambiaron todas las claves a GUID para que las fusiones pudieran ocurrir sin temor a colisiones de datos, incluso en tablas que no formaban parte de la fusión (en caso de que esas tablas se convirtieran en parte de una fusión futura).

Yo diría que un PK entero no te va a morder a menos que planees fusionar datos de fuentes separadas o que tengas datos que vayan más allá de tus límites de tamaño entero; todo es diversión y juegos hasta que te quedes sin espacio para inserciones .

Sin embargo, diré que puede tener sentido establecer su índice agrupado en una columna que no sea su PK, si la tabla se consultará con más frecuencia de esa manera. Pero ese es un caso atípico, especialmente si la mayoría de las actualizaciones y selecciones se basan en los valores de PK.


2
Suena como una justificación terrible para cambiar todas las claves a guías. Actualmente trabajo con una base de datos que usa guías para todas las claves sustitutas ... no es divertido.
Andy

2
No. Usar GUID no es divertido. No me gustan, pero respeto su valor en ciertos casos de uso.
CaM

2

Poniendo a un lado:

  • Las guerras religiosas (sustituto de google vs clave natural)
  • El tema separado de qué índices agrupados definir en sus tablas
  • La viabilidad de almacenar en caché todos sus datos

Siempre que esté usando la eliminación / actualización masiva cuando corresponda, y tenga índices para admitir tales operaciones, no creo que tenga problemas debido al estándar PK que usa.
Es posible que si luego tiene que EF genere consultas con combinaciones, etc., no serán tan eficientes como lo serían con un repositorio basado en claves naturales, pero no sé lo suficiente sobre esa área para decirlo de ninguna manera.


44
No puedo pensar en un solo caso en el que una combinación en una clave natural sería más eficiente que una combinación en un número entero: no muchas claves naturales pueden tener menos de 4 bytes, y si lo son, no puede haber suficientes unidades únicas. filas para hacer la diferencia material.
Aaron Bertrand

Para SQL competente y optimizable, estoy de acuerdo, pero me refería a posibles limitaciones de los generadores SQL. Mi única experiencia en esta área es que me pidan que cree vistas extensas con las que EF pueda alimentarse con cuchara, aunque es posible que los desarrolladores de .net no supieran lo suficiente sobre EF, o que hubiera otras razones.
TH

@AaronBertrand Diría que la única forma en que podrían ser más eficientes es si no se necesita una unión. Los únicos lugares en los que considero que el uso de claves naturales es con listas de códigos estándar como los códigos de moneda ISO4127 (que son reconocibles por el ser humano), y podría usar GBP, EUR, etc., como la clave foránea para una clave primaria o alternativa en el código de moneda mesa.
David Aldridge

@David Por supuesto, estaba hablando de casos donde las uniones son necesarias. Hay muchos casos en los que no quiero que la clave natural prolifere en todas las tablas relacionadas, porque las claves naturales pueden cambiar, y eso es algo doloroso.
Aaron Bertrand

Hmmm, veo cómo podría entenderse mal mi respuesta de estar promoviendo claves foráneas naturales en lugar de sustitutos. Para ser claros, en realidad solo los mencioné porque a) leí la pregunta de Alexei como "¿es un problema que no usemos claves naturales?", B) la pregunta de resumen de Alexei comenzó con "desde la perspectiva de un DBA" y yo sentí que debería reconocer que hay más de una perspectiva yc) porque creo que las características de ORM que se utilizarán en gran medida dictan la elección (si realmente puede hacer la diferencia). Estoy firmemente en el campo sustituto de claves extranjeras yo mismo.
TH

2

Tienes algunos factores para guiarte,

  1. Definición y espec.

    Si algo se define como único por la tarea o las leyes de la física, está desperdiciando su tiempo con una clave sustituta.

  2. Unicidad.

    Para la cordura personal, las uniones y la funcionalidad de base de datos de nivel superior, necesitará, (a) columna única, (b) serie única de columnas

    Todos los esquemas suficientemente normalizados (1NF) proporcionan uno de los siguientes. Si no lo hacen , siempre debes crear uno. Si tiene una lista de personas preparadas para ser voluntario el domingo, e incluye el apellido y el nombre, querrá saber cuándo tiene dos Joe Bobs.

  3. Implementación y optimización.

    Un int tiende a ser un pequeño formulario de datos que es rápido para la comparación y la igualdad. Compare eso con una cadena Unicode cuya clasificación puede depender de la configuración regional (ubicación e idioma). Almacenar un 4242 en una cadena ASCII / UTF8 es de 4 bytes. Al almacenarlo como un entero, cabe en 2 bytes.

Entonces, cuando se trata de inconvenientes, tienes algunos factores.

  1. Confusión y ambigüedad.

    1. La entrada de blog de @Aaron Bertrand resume esto bien. No es autodocumentado tener un OrderID por la especificación y la tarea, y luego imponer un " OrderID " a través de la implementación de la base de datos. A veces hay que aclarar eso o crear una convención, pero es probable que esto agregue confusión.
  2. Espacio.

    Los enteros aún agregan espacio a la fila. Y, si no los estás usando, no tiene ningún propósito

  3. Agrupación

    Solo puede solicitar sus datos de una manera. Si impone una clave sustituta que no es necesaria, ¿se agrupa de esa manera o de la clave natural?


Buenas y cortas ventajas y desventajas.
Alexei

@Alexei, gracias, considera marcarlo como elegido si cumple con lo que estás buscando. O, pidiendo aclaraciones.
Evan Carroll
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.