Quais são as maneiras eficientes de lidar com esquemas de banco de dados compartilhados entre ramificações de código?

12

Trabalhando em um projeto com várias ramificações, onde cada ramificação é eventualmente mesclada de volta à ramificação principal e, em essência, é isolada para desenvolver um novo recurso.

O banco de dados, que é o MS SQL Server, possui um esquema compartilhado, porém cada ramificação faz alterações no esquema à medida que avança.

Minha pergunta principal é quais são as boas maneiras de lidar com o compartilhamento do esquema da ramificação principal até a derivada, de modo que as alterações feitas na ramificação principal sejam facilmente mescladas na ramificação derivada, sem pisar em novas alterações na derivada. ramo?


fonte
2
Apenas a fusão deve ser tratada como qualquer outro código: mesclagem automática, com fallback da intervenção do usuário e inspeção / teste do resultado. (Prefiro a maneira como o projeto de banco de dados do VS lida com esquemas com um objeto por arquivo.). O complicado bit vem com a forma como a frente-migrações de trabalho bases de dados existentes ;-)
2
Isso depende muito de como você está versionando o esquema. Você está armazenando scripts de criação para os objetos base e scripts de alteração? Você está usando uma ferramenta de comparação de esquema para gerar scripts alter para migrar entre versões? Projetos de banco de dados VS2010?
Mark-Storey-Smith
Discussão relevante: dba.stackexchange.com/questions/2/…
Nick Chammas
1
Também relevante: martinfowler.com/articles/…
Nick Chammas

Respostas:

7

Utilizei com sucesso a seguinte metodologia, elaborada no Controle de Versão e no seu Banco de Dados :

  • manter um número de versão em metadados (eu uso uma propriedade estendida do banco de dados)
  • qualquer alteração de esquema é codificada como um script que é atualizado da versão atual para a próxima versão
  • O aplicativo é enviado com todos os scripts para atualizar da versão 0 (implantação inicial) até a versão atual
  • Toda mudança é feita através de um script. A inclusão de alterações de dados do 'sistema', como dicionários e entradas da tabela de pesquisa.
  • Quando implementado, o aplicativo verifica a versão do esquema em disco e executa todas as etapas de atualização para trazer o esquema para a versão necessária atual

Costumo ouvir a opinião de 'como isso é diferente de apenas manter os scripts de definição de objeto sob controle de origem?'. A diferença é enorme, porque quando você implanta uma nova versão do seu aplicativo, não cria simplesmente um novo banco de dados. Na maioria das vezes, seu aplicativo precisará atualizar o banco de dados existente, incluindo os dados existentes . Essa é uma diferença crucial. Suas etapas de atualização precisam garantir a integridade e a consistência dos dados existentes durante a atualização. Algumas operações são triviais no código (adicione uma coluna não anulável com valor padrão ao script de definição de objeto de tabela, concluído), mas na verdade são extremamente dolorosas na implantação real (a tabela possui 1,5 bilhão de linhas, a coluna de adição acabaria espaço de log, se feito da maneira "simplória").

Como isso funciona com a ramificação:

  • quando a ramificação é criada, ela captura a versão atual do esquema, por exemplo, versão 1.6
  • quando a equipe começa a trabalhar na filial, ela adiciona uma nova versão, 1.7, e começa a codificar a etapa de atualização de 1.6 para 1.7
  • a etapa de atualização é alterada conforme as modificações são feitas na ramificação. Ele sempre executa o script que atualiza da v 1.6 para a 1.7, mas o que exatamente esses scripts fazem está sujeito às iterações e check-ins normais de código na ramificação
  • Quando o ramo termina o desenvolvimento, ele se prepara para a integração reversa (a ser mesclada de volta à linha de base)
    • ele faz uma nova integração direta da linha de base à filial. Se a integração não trouxer alterações para a versão do esquema, tudo ficará bem, o ramo poderá reverter a integração como está. a versão 1.7 se torna a nova versão da linha de base.
    • o interessante é quando outro ramo se integra inversamente à base nesse meio tempo e agora a versão do esquema base foi alterada para, digamos, 1,7. Nesse caso, nossa filial precisa aumentar a versão do esquema de destino de implantação para 1.8 e fazer uma revisão da etapa de atualização que era anteriormente de 1.6 para 1.7 para ver como ela opera no novo ambiente, atualizando de 1.7 para 1.8. Os conflitos de esquema lógico precisam ser resolvidos, o script pode exigir alterações, o teste deve ser feito. Uma vez concluído, o ramo pode reverter a integração na base. A versão de destino implementada do produto agora é 1.8.
    • quando outro ramo que bifurcou na versão 1.6 do esquema quiser se integrar de forma reversa, ele precisará elevar sua versão do esquema para 1.9, testar o script de atualização de 1.8 para 1.9, para que possa se integrar novamente à base.

Observe que não há nenhuma ferramenta envolvida, nenhum script de diff de esquema mágico, nenhum assistente e nenhum script de botão direito do mouse gerado. Este é um processo 100% orientado ao desenvolvedor, baseado na fonte (scripts). Muitos acham todo esse processo elaborado, mas funciona. De fato, como usuário do SQL Server, você já aproveitou os resultados desse processo no uso diário do SQL Server: o próprio SQL Server usa um processo de atualização de banco de dados muito semelhante e, como você provavelmente espera, o processo de desenvolvimento de produtos faz uso extensivo de ramificação e o problema que você mencionou é um problema muito real que precisa ser resolvido.

BTW, como a ramificação / integração realmente ocorre difere entre os produtos de controle de origem, estou usando os termos familiares do modo de operação de integração forçada .

Remus Rusanu
fonte
+1, especialmente para Cada alteração é feita através de um script
a_horse_with_no_name
1

Embora minha resposta possa não ser tão longa quanto a de Remus, achei essa uma solução muito boa. Ainda não o configurei em produção, então YMMV *.

Liquibase

Essencialmente, é um arquivo XML em que você faz alterações de esquema no banco de dados como novos elementos dentro do arquivo XML. Por exemplo:

<createTable tableName="department">
            <column name="id" type="int">
                <constraints primaryKey="true" nullable="false"/>
            </column>

Ele possui uma sintaxe completa, para que você possa fazer o que quiser com o banco de dados.

Você também especifica em sua instalação do Liquibase qual banco de dados você deseja versionar. Em seguida, você "executa" o .xml com o executável Java incluído (arquivo jar). Isso essencialmente recria as alterações especificadas no XML no seu banco de dados.

O verdadeiro kicker é que você armazena esse arquivo XML na mesma pasta com versão do seu código. Então, no meu exemplo, esse foi o Git. Eu tinha esse arquivo XML na minha pasta do projeto (mesmo nível que /.git) e, sempre que eu alternava as ramificações, o arquivo XML mudava para essa versão da ramificação e eu executava o arquivo .jar e meu banco de dados agora refletia essa ramificação.

* Nota: Não concluí a implementação porque tive problemas para conectar o Java ao SQL Server. Precisa de alguns drivers jdbc e tal e eu não estava de bom humor. Portanto, sua milhagem pode variar.

MikeMurko
fonte
1

Aqui no Red Gate, lançaremos em breve uma solução de versão de banco de dados que aproveita o SQL Compare e o SQL Source Control. Isso usa uma abordagem de atualização de scripts de migração e carimba o banco de dados com uma propriedade estendida de versão que corresponde a uma revisão de controle de origem.

Esperamos lançar em meados de dezembro. Há um candidato a lançamento disponível agora. Para mais informações visite:

http://www.red-gate.com/products/sql-development/sql-source-control/entrypage/migration

Esperamos desenvolver essa solução nos próximos meses. Portanto, informe-nos o que você pensa.

David Atkinson
fonte
0

Se você e o seu esquema forem alterados gerando scripts e mantendo esses scripts sob controle de origem, poderá tratar as alterações como faria com qualquer outra mesclagem de código. Você pode optar por mesclar automaticamente ou realizar mais intervenções manuais.


fonte
Não, realmente não. A mesclagem manual de scripts de criação de objeto base é viável, mas é possível alterar, inserir inserções de dados de referência e scripts de movimento de dados muito confusos, muito rapidamente.
Mark-Storey-Smith #
Acordado. Aqui no Red Gate acreditamos que os scripts de criação se fundirão muito bem e podem ser automatizados. No entanto, os scripts de migração entre versões terão que ser mesclados manualmente para evitar pedidos de dependência incorretos e duplicação de código de alteração.
David Atkinson
0

Estou em uma situação semelhante em que trabalho em um site ativo e em várias ramificações de desenvolvimento nas quais preciso alterar o esquema do banco de dados.

Eu o resolvi escrevendo um post-checkout e um gancho pós-mesclagem que podem ser usados ​​com o git. Eu armazeno todas as minhas migrações na forma de arquivos SQL em um diretório separado e as confirmo junto com o código PHP alterado. Cada vez que executo um

git checkout

ou um

git merge

O git chamará automaticamente as migrações para cima e para baixo apropriadas. Veja minha implementação no Github .

Richard Brinkman
fonte