Cuando comienza a acceder a "campos definidos por el usuario", como se encuentra a menudo en los rastreadores de errores, la gestión de recursos del cliente y herramientas comerciales similares, es que no están respaldados con una tabla con miles de millones de campos (si lo están, entonces es probable que sea un problema de su propio).
En cambio, lo que encuentra son los diseños de tabla de Valor de atributo de entidad y la herramienta de administración asociada para administrar los atributos válidos.
Considere la siguiente tabla:
+ -------------- +
El | cosa |
| -------------- |
El | id |
El | tipo |
El | desc |
El | attr1 |
El | attr2 |
El | attr3 |
El | attr4 |
El | attr5 |
+ -------------- +
Esto es después de haber agregado algunos atributos. En lugar de attr1
pretender que lee artist
o tracks
o genre
o lo que sea atributos lo tiene. Y en lugar de 5, qué pasaría si fueran 50. Claramente eso es inmanejable. También requiere una actualización del modelo y la redistribución de la aplicación para manejar un nuevo campo. No es ideal.
Ahora considere la siguiente estructura de tabla:
+ -------------- + + --------------- + + ------------- +
El | cosa | El | thing_attr | El | attr |
| -------------- | | --------------- | | ------------- |
El | id | <--- + | thing_id (fk) | +> | id |
El | tipo | El | attr_id (fk) | + - + | nombre |
El | desc | El | valor | El | El |
+ -------------- + + --------------- + + ------------- +
Tienes lo tuyo con sus campos básicos. Tienes dos mesas más. Uno con los atributos. Cada campo es una fila en la attr
tabla. Y luego está el thing_attr
con un par de claves externas relacionadas con la thing
tabla y la attr
tabla. Y esto luego tiene un campo de valor donde se almacena el valor del campo para esa entidad.
Y ahora tiene una estructura donde la tabla de atributos se puede actualizar en tiempo de ejecución y se pueden agregar (o eliminar) nuevos campos sobre la marcha sin un impacto significativo en la aplicación general.
Las consultas son un poco más complejas y la validación se vuelve más compleja también (ya sea procedimientos almacenados funky o todo el lado del cliente). Es una compensación en el diseño.
Considere también la situación en la que algún día necesita hacer una migración y vuelve a la aplicación para encontrar que ahora hay media docena más o menos de atributos que el esquema que distribuyó originalmente. Esto permite migraciones y actualizaciones feas donde la tabla de valores de atributo de entidad, cuando se usa correctamente, puede ser más limpia. (No siempre, pero puede ser).
¿Hay alguna desventaja en modificar el esquema en tiempo de ejecución? Si el usuario cree que algo necesita un nuevo atributo, ¿solo agrega dinámicamente una columna a la tabla?
Si está trabajando con el sabor apropiado de la base de datos nosql, probablemente podría hacer esto (tenga en cuenta que el sabor apropiado del nosql para esto probablemente sería un almacén de valores clave que es, bueno, la tabla EAV para los relacionales descritos anteriormente) sin demasiados problemas Sin embargo , viene con todos los compromisos para nosql que se describen en otra parte con gran detalle.
Si, en cambio, está trabajando en una base de datos relacional, debe tener el esquema. Agregar la columna dinámicamente significa que algunos subconjuntos de las siguientes cosas son verdaderas:
- Estás haciendo programación de metabase de datos. En lugar de poder asignar limpiamente esta columna a ese campo con un buen ORM, probablemente esté haciendo cosas como
select *
y luego haciendo un código complejo para averiguar cuáles son realmente los datos (consulte ResultSetMetaData de Java ) y luego almacenarlos en un mapa ( o algún otro tipo de datos, pero no campos agradables en el código). Esto arroja un poco de seguridad tipográfica y tipográfica que tiene con el enfoque tradicional.
- Probablemente hayas abandonado el ORM. Esto significa que está escribiendo sql sin formato para todo el código en lugar de dejar que el sistema haga el trabajo por usted.
- Has renunciado a hacer actualizaciones limpias. ¿Qué sucede cuando el cliente agrega un campo con un nombre que también usa su próxima versión? En el sitio de emparejamiento, la actualización que desea agregar un
hasdate
campo para almacenar una marca de tiempo ya se ha definido como hasdate
un booleano para una coincidencia exitosa ... y su actualización se rompe.
- Estás confiando en que el cliente no interrumpe el sistema al usar alguna palabra reservada que también interrumpe tus consultas ... en alguna parte.
- Te has vinculado a una marca de base de datos. El DDL de diferentes bases de datos es diferente. Los tipos de bases de datos son el ejemplo más sencillo de esto.
varchar2
vs text
y similares. Su código para agregar la columna funcionaría en MySQL pero no en Postgres, Oracle o SQL Server.
- ¿Confía en el cliente para agregar realmente los datos así ? Claro, el EAV está lejos de ser ideal, pero ahora tiene algunos nombres de tabla oscuros y horrendos que el desarrollador no agregó, con el tipo incorrecto de índice (si corresponde), sin restricciones agregadas en el código donde es necesario ser y así sucesivamente.
- Le ha otorgado privilegios de modificación de esquema al usuario que ejecuta la aplicación. Little Bobby Drop Tables no es posible cuando está restringido a SQL en lugar de DDL (seguro que puede hacer un
delete * from students
cambio, pero realmente no puede estropear la base de datos de manera incorrecta). La cantidad de cosas que pueden salir mal con el acceso al esquema, ya sea por accidente o por actividad maliciosa, se dispara.
Esto realmente se reduce a "no lo hagas". Si realmente quiere esto, vaya con un patrón conocido de la estructura de la tabla EAV o una base de datos que esté completamente dedicada a esta estructura. No permita que las personas creen campos arbitrarios en una tabla. Los dolores de cabeza simplemente no valen la pena.