Dados de configuração: tabela de linha única vs. tabela de pares nome-valor

58

Digamos que você escreva um aplicativo que possa ser configurado pelo usuário. Para armazenar esses "dados de configuração" em um banco de dados, dois padrões são comumente usados.

  1. A tabela de linha única

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. A tabela nome-valor-par

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

Eu vi as duas opções em estado selvagem e ambas têm vantagens e desvantagens óbvias, por exemplo:

  • As tabelas de linha única limitam o número de opções de configuração que você pode ter (já que o número de colunas em uma linha geralmente é limitado). Cada opção de configuração adicional requer uma alteração de esquema do banco de dados.
  • Em uma tabela de pares nome-valor, tudo é "digitado" (você precisa codificar / decodificar seus parâmetros Boolean / Date / etc.).
  • (muitos mais)

Existe algum consenso dentro da comunidade de desenvolvimento sobre qual opção é preferível?

    
por Heinzi 04.09.2012 / 16:48
fonte

7 respostas

14

Eu pessoalmente prefiro as tabelas de linha única para a maioria das coisas. Embora seja verdade que é menos flexível, a menos que você esteja esperando um comportamento dinâmico, é perfeitamente aceitável adicionar colunas extras mais tarde, se necessário. De certa forma, é o equivalente a usar um dicionário / mapa para manter pares nome-valor versus ter membros da turma durante a programação. Concedido, não é uma metáfora perfeita, mas muitas das vantagens e desvantagens são paralelas quando você pensa sobre isso.

Então você usaria um dicionário / mapa sobre os membros da classe? Provavelmente não, a menos que você tenha motivos para pensar que a quantidade de dados a ser representada é totalmente adaptável, bem como ter uma tabela de pares de valores de nomes.

    
por 04.09.2012 / 16:58
fonte
12

Eu geralmente usaria a opção 2 MAS teria várias colunas para impor o tipo de dados

ConfigOption   |   textValue    |   DateValue   |   NumericValue

Opção 1 Tem o Benefício adicional de que você pode facilmente "Trocar" Configurações inteiras adicionando uma coluna Active .

    
por 04.09.2012 / 16:55
fonte
8

Para mim, se você usa linha única ou EAV depende de como você deseja consumi-los.

O poder do EAV é que novos dados podem ser adicionados sem alterar a estrutura. Isso significa que, se você quiser um novo valor de configuração, basta adicioná-lo à tabela e retirá-lo onde quiser no código, e não é necessário adicionar um novo campo ao domínio, esquema, mapeamento, consultas DAL etc.

Sua falha é que ele tem apenas a estrutura mais básica, exigindo que você lide com os dados de forma pessimista. Todo uso de qualquer valor de configuração deve esperar que o valor não esteja presente, ou não esteja no formato adequado, e se comportar de acordo quando não estiver. Um valor de configuração pode não ser analisável para um double, ou um int ou um char. Pode ser nulo. pode não haver nenhuma linha para o valor. As maneiras de contornar isso geralmente exigem um único valor válido "padrão" para existir para todos os valores de configuração de um determinado tipo de código ( extremamente raro; mais frequentemente o valor padrão é tão problemático para consumir código quanto none, ou manter um dicionário de valores padrão (que deve ser alterado toda vez que uma nova coluna é adicionada, tornando a vantagem principal do armazenamento EAV bastante discutível).

Uma única linha larga é praticamente o oposto. Você o mapeia para uma única instância de um objeto Configuration com um campo / propriedade para cada valor de configuração existente. Você sabe exatamente que tipo esses valores devem estar em tempo de compilação, e você "falha rapidamente" no DAL se uma coluna de configuração não existir ou não tiver um valor do tipo apropriado, dando a você um local para capturar exceções com base em problemas de recuperação de configuração / hidratação.

A principal desvantagem é que uma mudança estrutural é necessária para cada novo valor; nova coluna DB, nova coluna no DAL (o mapeamento ou as consultas SQL / SPs), nova coluna de domínio, tudo necessário para testar adequadamente o uso.

A situação adequada na qual usar um destes é a situação em que as desvantagens são mitigadas. Para mim, a maioria das situações para codificação de configuração requer uma implementação de linha única. Isto é principalmente porque se você está introduzindo um valor de configuração inteiramente novo que rege o comportamento de alguma parte do seu programa, você já tem que mudar o código para usar o novo valor de configuração; Por que não aparecer no objeto de configuração e adicionar o valor a ser usado?

Em suma, um esquema EAV para armazenar configurações realmente não resolve o problema que ele pretende resolver, e a maioria das soluções para os problemas que ele apresenta violam DRY.

    
por 04.09.2012 / 22:33
fonte
4

Especificamente para valores de configuração, eu diria - vá com a única linha. A menos que você esteja passando pelo desenvolvimento, com que frequência essas colunas vão mudar de qualquer maneira?

Provavelmente é melhor proteger o tipo de dados dos valores , em vez do código para a extensibilidade que você provavelmente não terá no tempo de inatividade entre as liberações grandes (r). Além disso, adicionar ou remover uma única coluna é a migração mais fácil que existe. Eu não vejo dor de cabeça ao criar uma nova opção de configuração.

Além disso, você disse que "usuários" podem configurar essas opções sem dar um limite. Eles são configurações por usuário? Se assim for, vou argumentar ainda mais strongmente que as opções de configuração devem estar nas colunas - uma única linha por usuário. Vai economizar muita dor de cabeça de manutenção mais tarde.

    
por 04.09.2012 / 23:13
fonte
1

Linha única Prós: bem definido. Contras: Mudar a configuração pode ser uma dor. Migrações de banco de dados, etc.

Valor da entidade Prós: Super flexível, suporta evoluir sua configuração. Contras: integridade referencial? Mais verificações no seu código para ver se a propriedade existe antes que você possa fazer qualquer coisa nela.

Eu tomaria a abordagem 2 apoiada por um banco de dados não-relacional como o Mongo. Se há algo de que você pode ter certeza, sua mudança.

    
por 04.09.2012 / 21:32
fonte
1

Use os dois!

Classifique quais opções podem ter várias instâncias e quais opções são genéricas.

A tabela de linha única (configurações)

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

A tabela de pares nome-valor (opções)

  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    
  ...              |  ...            | ...          

Acho que isso é mais flexível.

    
por 24.11.2016 / 10:10
fonte
1

Se seus clientes puderem processar fragmentos JSON (que não são apenas matrizes e dicionários, mas também strings simples, números, booleanos, valores nulos), você poderá ter uma tabela de várias linhas com nome de opção e um valor de cadeia contendo JSON. Isso permite armazenar também valores estruturados e o código para processá-los já deve estar lá.

Se seus clientes não puderem processar fragmentos JSON, consiga novos clientes.

    
por 24.11.2016 / 10:30
fonte