Debate de design:quais são boas maneiras de armazenar e manipular objetos versionados?[fechado]

StackOverflow https://stackoverflow.com/questions/11689

Pergunta

Estou intencionalmente deixando isso bastante vago no início.Procuro discussão e quais questões são mais importantes do que procuro respostas difíceis.

Estou projetando um aplicativo que faz algo como gerenciamento de portfólio.O design que tenho até agora é

  • Problema:um problema que precisa ser resolvido
  • Solução:uma proposta de solução para um ou mais problemas
  • Relação:uma relação entre dois problemas, duas soluções ou um problema e uma solução.Mais subdividido em:
    • Pai-filho - algum tipo de categorização/hierarquia de árvore
    • Sobreposição – o grau em que duas soluções ou dois problemas realmente abordam o mesmo conceito
    • Endereços - o grau em que um problema aborda uma solução

Minha pergunta é sobre a natureza temporal dessas coisas.Os problemas surgem e depois desaparecem.As soluções têm uma data prevista de resolução, mas que poderá ser modificada à medida que forem desenvolvidas.O grau de um relacionamento pode mudar com o tempo, à medida que os problemas e as soluções evoluem.

Então, a pergunta:qual é o melhor design para versionamento dessas coisas para que eu possa ter uma perspectiva atual e histórica do meu portfólio?

Mais tarde:talvez eu devesse fazer desta uma pergunta mais específica, embora a resposta de @Eric Beard valha a pena.

Considerei três designs de banco de dados.Vou falar o suficiente de cada um para mostrar suas desvantagens.Minha pergunta é:qual escolher ou você consegue pensar em algo melhor?

1:Os problemas (e separadamente, as soluções) são auto-referenciais no controle de versão.

table problems
  int id | string name | text description | datetime created_at | int previous_version_id

  foreign key previous_version_id -> problems.id

Isso é problemático porque toda vez que eu quero uma nova versão, tenho que duplicar a linha inteira, incluindo aquela longa description coluna.

2:Crie um novo tipo de relacionamento:Versão.

table problems
  int id | string name | text description | datetime created_at

Isso simplesmente move o relacionamento das tabelas Problemas e Soluções para a tabela Relacionamentos.O mesmo problema de duplicação, mas talvez um pouco mais "limpo", pois já tenho um conceito abstrato de Relacionamento.

3:Use uma estrutura mais parecida com o Subversion;mova todos os atributos de Problema e Solução para uma tabela separada e crie uma versão deles.

table problems
  int id

table attributes
  int id | int thing_id | string thing_type | string name | string value | datetime created_at | int previous_version_id

  foreign key (thing_id, thing_type) -> problems.id or solutions.id
  foreign key previous_version_id -> attributes.id

Isso significa que para carregar a versão atual de um Problema ou Solução tenho que buscar todas as versões do atributo, classificá-las por data e então usar a mais atual.Isso pode não ser terrível.O que parece muito ruim para mim é que não consigo verificar esses atributos no banco de dados.Que value coluna deve ser de texto livre.Eu posso fazer o name coluna uma referência em um separado attribute_names mesa que tem um type coluna, mas isso não força o tipo correto no attributes mesa.

mais tarde ainda:resposta aos comentários de @Eric Beard sobre chaves estrangeiras de múltiplas tabelas:

Infelizmente, o que descrevi é simplista:existem apenas dois tipos de coisas (problemas e soluções).Na verdade, tenho cerca de 9 ou 10 tipos diferentes de coisas, então teria 9 ou 10 colunas de chaves estrangeiras em sua estratégia.Eu queria usar herança de tabela única, mas as coisas têm tão pouco em comum que seria extremamente é um desperdício combiná-los em uma tabela.

Foi útil?

Solução

Hmm, soa meio como este site ...

Tanto quanto um projeto de banco de dados iria, um versionamento tipo sistema de como SVN, onde você nunca realmente fazer quaisquer alterações, apenas inserções (com um número de versão) quando as coisas mudam, pode ser o que você precisa. Isso é chamado de MVCC, Multi-Valor Controle de concorrência. Um wiki é outro bom exemplo disso.

Outras dicas

@Gaius

foreign key (thing_id, thing_type) -> problems.id or solutions.id

Tenha cuidado com esses tipos de chaves estrangeiras "multidirecional". Minha experiência tem mostrado que o desempenho da consulta sofre drasticamente quando sua condição de junção tem que verificar o tipo antes de descobrir qual tabela para juntar-se diante. Não parece tão elegante, mas anulável

problem_id and solution_id 

vai funcionar muito melhor.

Claro, consulta de desempenho vai também sofrem com um design MVCC quando você tem que adicionar a seleção para obter a última versão de um registro. A desvantagem é que você nunca tem que se preocupar com a disputa com atualizações.

Como você acha sobre isso:

problemas de mesa
int id | string name | descrição do texto | datetime created_at

problems_revisions tabela
revisão int | int id | string name | descrição do texto | datetime created_at
ID de chave estrangeira -> problems.id

Antes de atualizações que você tem que executar uma inserção adicional na tabela de revisão. Esta inserção adicional é rápido, no entanto, é isso que você tem que pagar por

  1. um acesso eficiente à versão atual - selecione problemas, como de costume
  2. um esquema que é intuitivo e perto da realidade que você quer modelo
  3. junções entre tabelas em seu esquema manter eficiente
  4. usando um número de revisão por transação busines você pode fazer versões mais registros da tabela como SVN faz mais arquivos.

Eu suponho que há

Opção 4: o híbrido

Mova o comum atributos coisa em uma tabela de herança simples, em seguida, adicione uma tabela custom_attributes. Isto faz-chaves estrangeiras mais simples, reduz a duplicação, e permite flexibilidade. Não resolve os problemas de tipo de segurança para os atributos adicionais. Ele também adiciona um pouco de complexidade uma vez que existem duas maneiras de uma coisa para ter um atributo agora.

Se description e outros grandes campos de permanecer na tabela de coisas, porém, também não resolve o problema de duplicação-espaço.

table things
  int id | int type | string name | text description | datetime created_at | other common fields...
  foreign key type -> thing_types.id

table custom_attributes
  int id | int thing_id | string name | string value
  foreign key thing_id -> things.id

É uma boa idéia para escolher uma estrutura de dados que faz perguntas comuns que você perguntar do modelo fácil de responder. É mais provável que você está interessado na posição atual na maioria das vezes. Na ocasião, você vai querer furar a história para determinados problemas e soluções.

Eu teria tabelas para problema, solução, ea relação que representam a posição atual. Haveria também uma mesa problem_history, solution_history, etc. Estes seriam tabelas filho de problema, mas também conter colunas extras para VersionNumber e EffectiveDate. A chave seria (ProblemId, VersionNumber).

Quando você atualizar um problema, você iria escrever os valores antigos na tabela de problem_history. Ponto em consultas de tempo são, portanto, possível, como você pode escolher o recorde problem_history que é válido como-em uma data particular.

Onde eu fiz isso antes, eu também criaram vista a UNIÃO problem e problem_history como isso às vezes é útil em várias consultas.

Opção 1 torna difícil para consultar a situação atual, como todos os seus dados histórico é misturado com os dados atuais.

Opção 3 vai ser ruim para o desempenho da consulta e desagradável ao código contra como você vai estar acessando lotes de linhas para o que deveria ser apenas uma simples consulta.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top