¿Es una mala práctica permitir campos definidos por el usuario?

17

En términos generales, ¿se considera una mala práctica permitir campos creados por el usuario en una base de datos para una aplicación web?

Por ejemplo, estoy haciendo una aplicación web de inventario de viviendas para mi esposa, y ella querrá definir sus propios campos para diferentes artículos. Estaba planeando permitirle crear categorías de elementos y agregar "características" a esas categorías. Las características solo serían clave / valor almacenado como cadenas. De esa manera, si tuviera una categoría llamada "CD de audio", por ejemplo, podría agregar características para cosas como "artista", "pistas", etc. Pero en otra categoría como "muebles", podría agregar características para cosas como "material". "(madera, plástico, etc.). Entonces, cualquier elemento podría pertenecer a una (o muchas) categorías, agregando esas características al elemento.

Puedo ver problemas en los que la búsqueda por estas características requiere comparaciones de cadenas, no hay validación de datos, etc. Siguiendo una metodología ágil, tal vez sería mejor simplemente tener nuevas categorías y atributos y simplemente tendría que crear nuevas tablas a medida que avanzamos. En mi ejemplo, es una pequeña base de usuarios (2 de nosotros) y la cantidad de registros creados sería pequeña, por lo que no está tan mal.

Sin embargo, en términos generales, ¿cómo manejan las personas algo como esto en la "vida real"?

zako42
fuente
44
¿Ha considerado usar una base de datos orientada a documentos como MongoDB? Puede almacenar un documento por tipo que actúa como un esquema que también puede editarse (probablemente de forma manual, dada la pequeña escala del proyecto).
Andy Hunt
@AndyBursh uno de los bits 'divertidos' con postgres actuales es el tipo de datos 'json' ( enlace ). Tal enfoque le permitiría a uno almacenar campos especificados por el usuario en esos datos, er, documento, er, lo que sea y luego usar el resto de los campos para las cosas sobre las que indexa correctamente y similares. Aunque todo esto depende del uso y es difícil decir si funcionaría bien para una aplicación en particular o no. Pero es algo a tener en cuenta.
todos: gran discusión, gracias por toda la información! @AndyBursh He oído hablar de MongoDB, pero nunca he leído nada al respecto. Suena como otro proyecto de casa para experimentar ...
zako42

Respuestas:

19

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 attr1pretender que lee artisto trackso genreo 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 attrtabla. Y luego está el thing_attrcon un par de claves externas relacionadas con la thingtabla y la attrtabla. 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 hasdatecampo para almacenar una marca de tiempo ya se ha definido como hasdateun 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. varchar2vs texty 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 studentscambio, 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.

DougM
fuente
44
También ha reinventado la base de datos.
user253751
1
@immibis ha agregado una capa en la que el usuario puede administrar sin alterar el resto de la base de datos o requerir una redistribución para actualizar el modelo.
1
@immibis EAV ha debatido acaloradamente en los círculos de bases de datos relacionales durante años. En teoría, es innecesario, pero en la práctica, no puedes hacer ciertas cosas sin él.
Ross Patterson
1
@ShivanDragon que va al enfoque NoSQL. El almacén de documentos solo almacena documentos y no impone un esquema. Como tal, agregar y eliminar campos y analizar los documentos está completamente fuera del alcance de la base de datos en sí (y ha escrito su modelo para acomodar eso). Es un conjunto de compromisos completamente diferente que los compromisos de la base de datos relacional para una estructura EAV.
1
Discusión de chat relacionada: sobre alternativas de diseño de base de datos a eav
5

Hacer esto bien es difícil.

Para una aplicación única como la que está planeando, puede, por supuesto, agregar una columna para cada campo y proporcionar una interfaz de usuario que haga que la definición de campo por parte de usuarios no capacitados sea más segura que darles una línea de comando SQL. O puede seguir el temido patrón Entidad-Atributo-Valor , que es una respuesta clásica, aunque algo aterradora, a este tipo de problema. La creación de la interfaz de usuario para definir campos EAV suele ser mucho más compleja que para las columnas de la base de datos, y las consultas pueden ser bastante complicadas, pero para grandes cantidades de campos ( es decir , esquemas de matriz muy dispersa), puede ser la única forma de obtener El trabajo hecho.

Ross Patterson
fuente
En resumen: pequeño proyecto == KISS. Ágil hasta el suelo.
Encaitar
El problema con las actualizaciones de la tabla de la base de datos es que, dependiendo de la cantidad de datos y los índices requeridos (los campos personalizados a menudo requieren funciones de búsqueda), la consulta de alteración de la tabla puede tomar una cantidad enorme de tiempo. En pocas palabras, MySQL y otras bases de datos relacionales simplemente no son un buen medio para este tipo de requisitos.
Oddman
0

Encontré una cruz algo similar recientemente.

Hice 2 mesas.

1: table Objects 
    Id , name, type

Él es todos tus objetos. U establece su nombre.

Y un tipo de este objeto: - para mí, los tipos disponibles eran inventario, inventario_artículo, oficina.

Y la configuración habitual era n elementos son secundarios o inventario, que también es secundario de la oficina y utilicé una tabla de unión para unir objetos entre sí

2 table settings 
     organization_Id , title, value , type

La tabla de configuración contiene cada nombre de campo para ese tipo de objeto específico y valor en valor.

Ejemplo de propiedades de oficina

Ubicación, teléfono, horario laboral

Y para artículos

  • Cantidad
  • Precio
  • Código de barras

Etc, todas estas propiedades son aplicadas por su modelo y guardadas en la tabla de configuración como filas separadas (sin embargo, use reemplazar no insertar para evitar varias filas para el mismo campo)

Entonces, cuando quiero una oficina, la cargo fácilmente con todas sus relaciones y configuraciones donde la configuración object_I'd (objetos solicitados)

Después de eso, giro todas las filas desde la configuración y eso es todo.

Y en caso de que quisiera que una configuración sea específica para un artículo en un inventario (no global) configuré object_I'd = lo haría de la tabla de relaciones object_objects y configuré settings.type = relationship_setting

Espero que entiendan lo que quiero decir. Intentaré reformatear la respuesta cuando llegue a una computadora portátil.

Zalaboza
fuente
2
Consejo profesional: no publiques en este foro desde tu teléfono. La corrección automática hace que partes de tu publicación sean ilegibles.
BobDalgleish
Jaja bonita observación :)
Zalaboza
0

¿Es una mala práctica permitir campos definidos por el usuario?

No, no es una mala práctica. Es bastante común. En términos OO, esto se llama herencia. Tiene un inventario de clase base Item y dos clases heredadas AudioCD y mobiliario.

Sin embargo, en términos generales, ¿cómo manejan las personas algo como esto en la "vida real"?

Tiene que decidir cómo se almacenan en la base de datos del inventario de artículos, CD de audio y muebles.

Si la consulta fácil es lo más importante para usted y db-space / normalization no importa, implementaría el esquema de "tabla por jerarquía".

Si el espacio / normalización es lo más importante para usted y las consultas más complicadas no son un problema, implementaría el esquema "tabla por tipo".

Para obtener más detalles, consulte dotnet table-per-type-vs-table-per-Jerarquía-herencia o herencia de hibernación de Java .

k3b
fuente
No sé si esto responde a la pregunta. El usuario no está modificando el código para crear nuevas clases
Colin D