Datos de configuración: tabla de una sola fila frente a tabla de pares de nombre-valor


64

Supongamos que escribe una aplicación que el usuario puede configurar. Para almacenar estos "datos de configuración" en una base de datos, se usan comúnmente dos patrones.

  1. La tabla de una sola fila

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. La tabla de pares de nombre-valor

      ConfigOption   |   Value
    -----------------+-------------
     CompanyName     | ACME Inc.
     StartFullScreen | true (or 1, or Y, ...)
     RefreshSeconds  | 20
     ...             | ...
    

He visto ambas opciones en la naturaleza, y ambas tienen ventajas y desventajas obvias, por ejemplo:

  • Las tablas de una sola fila limitan la cantidad de opciones de configuración que puede tener (ya que la cantidad de columnas en una fila generalmente es limitada). Cada opción de configuración adicional requiere un cambio de esquema de base de datos.
  • En una tabla de pares de nombre-valor todo se "escribe en cadena" (debe codificar / decodificar sus parámetros booleanos / Fecha / etc.).
  • (mucho mas)

¿Existe algún consenso dentro de la comunidad de desarrollo sobre qué opción es preferible?


2
No hay razón para que el enfoque 'vertical' no pueda tener diferentes tipos de datos. Agregue una columna int, float y text por fila. Guardar / cargar valores utilizando funciones específicas del tipo, como 'SaveConfigInt (' field ', n)'
GrandmasterB

44
Hay una excelente pregunta de StackOverflow que se pregunta sobre esto, y la respuesta principal da ventajas y desventajas a ambos enfoques. stackoverflow.com/questions/2300356/…
Kevin - Reinstale Monica el

1
Enfoque 3: columna simple / fila única con un formato de intercambio de datos simple como JSON o YAML. Combina ventajas de ambos enfoques.
schlamar

¿qué pasa con el uso de una tabla de una sola fila con datos complejos que contienen xml / json como <config> <CompanyName> ACME Inc. </CompanyName> <StartFullScreen> true </StartFullScreen>20<RefreshSeconds></RefreshSeconds> </config> y validar objeto en la capa empresarial?
John

1
@ John: Buena idea, si se necesitan estructuras jerárquicas. Si no lo son, es solo la opción 2 con mayor complejidad.
Heinzi

Respuestas:


15

Personalmente prefiero las tablas de una sola fila para la mayoría de las cosas. Si bien es cierto que es menos flexible, a menos que espere un comportamiento dinámico, es perfectamente aceptable agregar columnas adicionales más adelante si es necesario. En cierto modo, es el equivalente a usar un diccionario / mapa para mantener pares de nombre-valor frente a tener miembros de la clase al programar. De acuerdo, no es una metáfora perfecta, pero muchas de las ventajas y desventajas son paralelas cuando lo piensas.

Entonces, ¿utilizarías un diccionario / mapa sobre los miembros de la clase? Probablemente no, a menos que tenga razones para pensar que la cantidad de datos a representar es totalmente adaptable, al igual que tener una tabla de pares de nombre y valor.


¿Qué pasa si los datos a almacenar están definidos por el usuario? es decir, piense en una IU donde el usuario pueda crear un "campo" especificando la etiqueta del campo, el tipo de datos que contendrá, etc. Eso significaría ejecutar sentencias DDL desde el código. ¿Seguirías con la opción 1?
devanalyst

1
@devanalyst No, si los datos pudieran cambiar de un componente a otro, entonces no tendría sentido intentar crear una tabla estática para representarlo. En ese caso, sería mejor usar la segunda opción.
Neil

12

En general, iría con la opción 2 PERO tendría varias columnas para aplicar el tipo de datos

ConfigOption   |   textValue    |   DateValue   |   NumericValue

La opción 1 tiene el beneficio adicional de que puede "intercambiar" configuraciones completas fácilmente agregando una Activecolumna.


Si va a permitir que se deshabiliten las configuraciones (para la opción 1), al menos activatedOnhágalo una marca de tiempo, para que pueda saber cuándo se activó. Y si va con la opción 2 ... ¿qué sucede si terminan almacenando valores en varias columnas (o es Oracle, donde (aparentemente) nulo y una cadena vacía son equivalentes)?
Clockwork-Muse

1
@ X-Zero, el almacenamiento de múltiples configuraciones generalmente se realiza con fines de prueba, pero una marca de tiempo no puede hacer daño. El mantenimiento de la configuración, llame para obtener el valor sabría qué columna verificar, si realmente quisiera, podría agregar una columna para el tipo de datos ... Pero creo que eso es más de matar ...
Morons

55
un esquema EATV (Entity-Attribute-Type-Value) rompe la tercera forma normal; la columna Tipo solo está relacionada indirectamente con la clave principal de la tabla, a través de la columna Valor que describe la columna Tipo. Además, el almacenamiento de tipo dinámico y la creación de instancias no resuelve mucho; si un método GetConfigValue () puede devolver cualquier tipo, debe devolver Object (o recibir el tipo esperado de alguna manera) que aún debe evaluarse en tiempo de ejecución.
KeithS

55
Cada vez que la opción 1 se ha implementado en el software que he visto, tenía que convertirse a la opción 2. La opción 2 es más fácil de mantener con el tiempo, solo toma un poco más de tiempo implementarla correctamente la primera vez. La opción 1 es rápida y fácil de implementar, pero el mantenimiento a lo largo del tiempo es horrible a menos que su software sea pequeño y no tenga posibilidades de crecer.
Jimmy Hoffa

8

Para mí, si vas a una sola fila o EAV depende de cómo quieras consumirlos.

El poder de EAV es que se pueden agregar nuevos datos sin cambiar la estructura. Esto significa que si desea un nuevo valor de configuración, simplemente agréguelo a la tabla y extráigalo donde lo desee en el código, y no necesita agregar un nuevo campo al dominio, esquema, mapeo, consultas DAL etc.

Su defecto es que solo tiene la estructura más simple, lo que requiere que usted trate los datos de manera pesimista. Cada uso de cualquier valor de configuración debe esperar que el valor no esté presente o no esté en el formato adecuado, y se comportará en consecuencia cuando no lo esté. Un valor de configuración puede no ser analizable a un doble, o un int, o un char. Puede ser nulo. puede que no haya una fila para el valor en absoluto. Las formas de evitar esto generalmente requieren que exista un único valor "predeterminado" válido para todos los valores de configuración de un tipo en código particular ( extremadamente raro; más a menudo el valor predeterminado es tan problemático para consumir código como ninguno), o para mantenga un diccionario codificado de valores predeterminados (que debe cambiar cada vez que se agrega una nueva columna, lo que hace que la ventaja principal del almacenamiento EAV sea bastante discutible).

Una sola fila ancha es más o menos lo contrario. Lo asigna a una sola instancia de un objeto de Configuración con un campo / propiedad para cada valor de configuración existente. Usted sabe exactamente qué tipo de valores deberían ser esos en el momento de la compilación, y "falla rápidamente" en el DAL si no existe una columna de configuración o no tiene un valor del tipo adecuado, lo que le brinda un lugar para detectar excepciones basadas en la recuperación de la configuración / problemas de hidratación.

La principal desventaja es que se requiere un cambio estructural para cada nuevo valor; nueva columna de DB, nueva columna en el DAL (ya sea la asignación o las consultas / SP de SQL), nueva columna de dominio, todo lo necesario para probar adecuadamente el uso.

La situación adecuada para utilizar cualquiera de estos es la situación en la que se mitigan las desventajas. Para mí, la mayoría de las situaciones para la codificación de configuración han requerido una implementación de una sola fila. Esto se debe principalmente a que si está introduciendo un valor de configuración completamente nuevo que rige el comportamiento de alguna parte de su programa, ya debe cambiar el código para usar el nuevo valor de configuración; ¿Por qué no aparece el objeto de configuración y agrega el valor que se utilizará?

En resumen, un esquema EAV para almacenar la configuración realmente no resuelve el problema que pretende resolver, y la mayoría de las soluciones a los problemas que presenta violan DRY.


3

Específicamente para los valores de configuración, diría: vaya con la fila única. A menos que esté actualmente en proceso de desarrollo, ¿con qué frecuencia van a cambiar esas columnas de todos modos?

Probablemente sea mejor asegurar el tipo de datos de los valores , en lugar del código de extensibilidad que no es probable que tenga en el tiempo de inactividad entre versiones grandes (r). Además, agregar o eliminar una sola columna es la migración más fácil que existe. No preveo un dolor de cabeza al crear una nueva opción de configuración.

Además, usted dijo que los "usuarios" pueden configurar estas opciones, sin dar un límite. ¿Son configuraciones por usuario? Si es así, argumentaré aún más firmemente que las opciones de configuración deberían estar en las columnas: una sola fila por usuario. Ahorrará muchos dolores de cabeza de mantenimiento más adelante.


2

Si sus clientes pueden procesar fragmentos JSON (que no son solo matrices y diccionarios, sino también cadenas simples, números, booleanos, valores nulos), entonces puede tener una tabla de varias filas con el nombre de la opción y un valor de cadena que contenga JSON. Eso le permite también almacenar valores estructurados, y el código para procesarlos ya debería estar allí.

Si sus clientes no pueden procesar fragmentos JSON, obtenga nuevos clientes.


1

Fila individual Pros: bien definido. Contras: Cambiar la configuración puede ser una molestia. Migraciones de bases de datos, etc.

Entity-Value Pros: Súper flexible, admite la evolución de su configuración. Contras: integridad referencial? Más verificaciones en su código para ver si la propiedad existe antes de que pueda hacer algo al respecto.

Tomaría el enfoque 2 respaldado por un db no relacional como Mongo. Si hay algo de lo que puede estar seguro, es el cambio.


1

¡Usa ambos!

Clasifique qué opciones pueden tener varias instancias y qué opciones son genéricas.

La tabla de una sola fila (configuraciones)

  id  |  company_name  |  start_fullscreen  |  refresh_seconds  |  ...
------+----------------+--------------------+-------------------+-------
  4   |  ACME Inc.     |  true              |  20               |  ...

La tabla de pares de nombre-valor (opciones)

  name             |  value          | update_time  
-------------------+-----------------+--------------
  generic_option_1 |  Option 1 Value | timestamp    
  generic_option_2 |  Option 2 Value | timestamp    
  generic_option_3 |  Option 3 Value | timestamp    
  configuration    |  4              | timestamp    
  ...              |  ...            | ...          

Creo que esto es más flexible.

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.