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 ( Int32
en C #, int
en 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 table
seguida (*) 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 SELECTs
no llegarán a la base de datos. Un patrón típico es la carga inicial y muchos INSERT
s, UPDATE
sy DELETE
s.
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:
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,
IDENTITY
se 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 ."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.
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
Limitaciones de Entity Framework : se permiten PK de varias columnas, pero sus valores no se pueden actualizar
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 -> value
mapa.
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:
Vistas de lista : no generará
SELECT
consultas 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.
Editar vistas : generará
SELECT
declaraciones como esta:SELECT allcolumns FROM BigTable WHERE PKId = value1
(todos los filtros y valores son int
s)
Respuestas:
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.
fuente
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_ID
seguirá 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:m
las tablas de asociación porque para esas tablas las ID de las entidades asociadas deben formar una clave primaria. Un contraejemplo sería unan:m
asociació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.fuente
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.
fuente
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.
fuente
Poniendo a un lado:
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.
fuente
Tienes algunos factores para guiarte,
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.
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.
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.
Confusión y ambigüedad.
Espacio.
Los enteros aún agregan espacio a la fila. Y, si no los estás usando, no tiene ningún propósito
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?
fuente