Como você deve construir seu banco de dados do controle de origem?

103

Houve alguma discussão no wiki da comunidade SO sobre se os objetos de banco de dados devem ser controlados por versão. No entanto, não vi muita discussão sobre as melhores práticas para criar um processo de automação de construção para objetos de banco de dados.

Esse tem sido um ponto de discussão controverso para minha equipe - principalmente porque os desenvolvedores e DBAs costumam ter objetivos, abordagens e preocupações diferentes ao avaliar os benefícios e riscos de uma abordagem de automação para implantação de banco de dados.

Eu gostaria de ouvir algumas idéias da comunidade SO sobre quais práticas têm sido eficazes no mundo real.

Sei que é um tanto subjetivo quais práticas são realmente melhores, mas acho que um bom diálogo sobre qual trabalho pode ser útil para muitas pessoas.

Aqui estão algumas das minhas perguntas preliminares sobre áreas de interesse neste tópico. Não se trata de uma lista definitiva, mas sim de um ponto de partida para as pessoas entenderem o que procuro.

  1. Os ambientes de teste e produção devem ser criados a partir do controle de origem?
    • Ambos devem ser desenvolvidos usando automação - ou a produção deve ser construída copiando objetos de um ambiente de teste finalizado e estável?
    • Como você lida com as diferenças potenciais entre os ambientes de teste e produção em scripts de implantação?
    • Como você testa se os scripts de implantação funcionarão de maneira tão eficaz na produção quanto no teste?
  2. Quais tipos de objetos devem ter controle de versão?
    • Apenas código (procedimentos, pacotes, gatilhos, java, etc)?
    • Índices?
    • Restrições?
    • Definições de tabela?
    • Scripts de mudança de tabela? (por exemplo, scripts ALTER)
    • Tudo?
  3. Quais tipos de objetos não devem ter controle de versão?
    • Sequências?
    • Bolsas?
    • Contas de usuário?
  4. Como os objetos de banco de dados devem ser organizados em seu repositório SCM?
    • Como você lida com coisas únicas, como scripts de conversão ou scripts ALTER?
    • Como você lida com a retirada de objetos do banco de dados?
    • Quem deve ser responsável por promover objetos desde o desenvolvimento até o nível de teste?
    • Como você coordena as mudanças de vários desenvolvedores?
    • Como você lida com a ramificação de objetos de banco de dados usados ​​por vários sistemas?
  5. Que exceções, se houver, podem ser feitas razoavelmente neste processo?
    • Problemas de segurança?
    • Dados com problemas de desidentificação?
    • Scripts que não podem ser totalmente automatizados?
  6. Como você pode tornar o processo resiliente e aplicável?
    • Erro de desenvolvedor?
    • Para questões ambientais inesperadas?
    • Para recuperação de desastres?
  7. Como você convence os tomadores de decisão de que os benefícios do DB-SCM realmente justificam o custo?
    • Provas anedóticas?
    • Pesquisa da indústria?
    • Recomendações de práticas recomendadas do setor?
    • Apelos a autoridades reconhecidas?
    • Análise de custo-benefício?
  8. Quem deve "possuir" objetos de banco de dados neste modelo?
    • Desenvolvedores?
    • DBAs?
    • Analistas de dados?
    • Mais de um?
LBushkin
fonte
3
A profundidade desta questão implora por uma recompensa.
Greg D
Consulte também stackoverflow.com/questions/115369/…
Tim Abell

Respostas:

53

Aqui estão algumas respostas às suas perguntas:

  1. Os ambientes de teste e produção devem ser criados a partir do controle de origem? SIM
    • Ambos devem ser desenvolvidos usando automação - ou a produção deve ser construída copiando objetos de um ambiente de teste finalizado e estável?
    • Automação para ambos. NÃO copie dados entre os ambientes
    • Como você lida com as diferenças potenciais entre os ambientes de teste e produção em scripts de implantação?
    • Use modelos, de forma que realmente você produza diferentes conjuntos de scripts para cada ambiente (por exemplo, referências a sistemas externos, bancos de dados vinculados, etc)
    • Como você testa se os scripts de implantação funcionarão de maneira tão eficaz na produção quanto no teste?
    • Você os testa no ambiente de pré-produção: teste a implantação na cópia exata do ambiente de produção (banco de dados e potencialmente outros sistemas)
  2. Quais tipos de objetos devem ter controle de versão?
    • Apenas código (procedimentos, pacotes, gatilhos, java, etc)?
    • Índices?
    • Restrições?
    • Definições de tabela?
    • Scripts de mudança de tabela? (por exemplo, scripts ALTER)
    • Tudo?
    • Tudo, e:
      • Não se esqueça de dados estáticos (listas de pesquisa etc), então você não precisa copiar NENHUM dado entre ambientes
      • Manter apenas a versão atual dos scripts de banco de dados (versão controlada, é claro), e
      • Armazene scripts ALTER: 1 script BIG (ou diretório de scripts nomeado como 001_AlterXXX.sql, de modo que executá-los em ordem de classificação natural será atualizado da versão A para B)
  3. Quais tipos de objetos não devem ter controle de versão?
    • Sequências?
    • Bolsas?
    • Contas de usuário?
    • consulte 2. Se seus usuários / funções (ou nomes de usuário técnicos) forem diferentes entre os ambientes, você ainda pode criar um script para eles usando modelos (consulte 1.)
  4. Como os objetos de banco de dados devem ser organizados em seu repositório SCM?
    • Como você lida com coisas únicas, como scripts de conversão ou scripts ALTER?
    • veja 2.
    • Como você lida com a retirada de objetos do banco de dados?
    • excluído do banco de dados, removido do tronco / ponta de controle de origem
    • Quem deve ser responsável por promover objetos desde o desenvolvimento até o nível de teste?
    • dev / teste / cronograma de lançamento
    • Como você coordena as mudanças de vários desenvolvedores?
    • tente NÃO criar um banco de dados separado para cada desenvolvedor. você usa o controle de origem, certo? neste caso, os desenvolvedores alteram o banco de dados e fazem o check-in dos scripts. para ficar completamente seguro, recrie o banco de dados a partir dos scripts durante a compilação noturna
    • Como você lida com a ramificação de objetos de banco de dados usados ​​por vários sistemas?
    • difícil: tente evitar a todo custo.
  5. Que exceções, se houver, podem ser feitas razoavelmente neste processo?
    • Problemas de segurança?
    • não armazene senhas para teste / produção. você pode permitir isso para desenvolvimento, especialmente se você automatizou reconstruções de banco de dados diárias / noturnas
    • Dados com problemas de desidentificação?
    • Scripts que não podem ser totalmente automatizados?
    • documentar e armazenar com as informações de lançamento / script ALTER
  6. Como você pode tornar o processo resiliente e aplicável?
    • Erro de desenvolvedor?
    • testado com a construção diária a partir do zero e compare os resultados com a atualização incremental (da versão A para B usando ALTER). compare o esquema resultante e os dados estáticos
    • Para questões ambientais inesperadas?
    • usar controle de versão e backups
    • compare o esquema do banco de dados PROD com o que você pensa, especialmente antes da implementação. SuperDuperCool DBA pode ter corrigido um bug que nunca existiu em seu sistema de tíquetes :)
    • Para recuperação de desastres?
  7. Como você convence os tomadores de decisão de que os benefícios do DB-SCM realmente justificam o custo?
    • Provas anedóticas?
    • Pesquisa da indústria?
    • Recomendações de práticas recomendadas do setor?
    • Apelos a autoridades reconhecidas?
    • Análise de custo-benefício?
    • se os desenvolvedores e DBAs concordarem, você não precisa convencer ninguém, eu acho (a menos que você precise de dinheiro para comprar um software como um dbGhost para MSSQL)
  8. Quem deve "possuir" objetos de banco de dados neste modelo?
    • Desenvolvedores?
    • DBAs?
    • Analistas de dados?
    • Mais de um?
    • Normalmente, os DBAs aprovam o modelo (antes do check-in ou depois como parte da revisão do código). Eles definitivamente possuem objetos relacionados ao desempenho. Mas, em geral, a equipe é a proprietária [e o empregador, é claro :)]
van
fonte
Obrigado pela sua resposta! Você acha que essas recomendações se aplicam a todos os projetos? Você conhece alguma ferramenta que o ajude a atingir esse nível de automação? Eu estarei atualizando minha pergunta conforme mais pessoas pesem nela. Além disso, esteja ciente de que minhas perguntas "provocadoras" não pretendiam ser uma lista definitiva de preocupações a serem abordadas - mas mais um ponto de partida para discussão.
LBushkin
Claro. Acho que você levantou uma pergunta muito boa. E eu realmente espero que a questão tenha tração suficiente para que você compile um ótimo wiki HowTo sobre o assunto. ---- das ferramentas: Usei dbGhost da Innovartis, que mencionei nas respostas para gerenciar o servidor MSSQL e fez um ótimo trabalho. Provavelmente, existem outras ferramentas para o trabalho, mas considerando que o esquema SQL completo não é realmente padrão entre os fornecedores, não existe uma solução completa (para todos os SCM e RDMBS).
van
Boa resposta. Estou assumindo que "listas de pesquisa" significam os dados usados ​​para preencher as caixas <select>. Isso nem sempre é possível, já que os dados podem ser modificados pelos usuários (de alguma forma) na produção. Manter backups faz sentido neste caso. Você também sugere recriar o banco de dados do zero como parte de uma construção noturna. Não acho que seja uma boa ideia; ele pode excluir o trabalho em andamento ou exigir a reinstalação / configuração de outro software. Por fim, sugiro criar modos de teste, validadores de dados e outras ferramentas, em vez de construir do zero para garantir processos resilientes.
Richard Levasseur
@Richard. Bons pontos, mas ainda assim. Quando você lê "construir um banco de dados do zero", nem sempre significa excluir os dados. É reconstruir o esquema e os dados estáticos. Se houver algum trabalho em andamento (em relação ao esquema ou dados estáticos), ele deve estar no controle de origem, portanto, fará parte da compilação noturna. Se você trabalha na filial com um grande redesenho de banco de dados, você tem um banco de dados separado para esse tipo de desenvolvimento. E se você usar testes de unidade, você não dependerá do status dos dados no banco de dados, mas criará / excluirá como parte do teste de unidade db. --- Dados estáticos dispensáveis ​​pelos usuários - concordo.
van
Não concordo com a reconstrução de bancos de dados todas as noites. Embora tudo para definir o banco de dados, como esquemas, gatilhos, procedimentos armazenados e certos dados estáticos "gerenciados" devam ser programados, o material real não deve ser. O conteúdo em si pode ser conduzido por tarefas do desenvolvedor. Temos desenvolvedores que trabalham em conjuntos de dados para teste e experimentação. E se eles chegassem todos os dias e seu estado atual fosse "reiniciado"? Não é bom. Eu uso testes TestNG que eliminam certas tabelas e, em seguida, pré-carregam os dados de teste todos os dias. Não soa como um candidato ao controle de origem.
gregturn
5

Eu trato o SQL como código-fonte quando possível

Se eu puder escrevê-lo no SQL compatível com o padrão, ele geralmente vai para um arquivo no meu controle de origem. O arquivo definirá o máximo possível, como SPs, instruções Table CREATE.

Também incluo dados fictícios para teste no controle de origem:

  1. proj / sql / setup_db.sql
  2. proj / sql / dummy_data.sql
  3. proj / sql / mssql_specific.sql
  4. proj / sql / mysql_specific.sql

E então eu abstraio todas as minhas consultas SQL para que eu possa construir o projeto inteiro para MySQL, Oracle, MSSQL ou qualquer outra coisa.

A automação de compilação e teste usa esses scripts de compilação, pois eles são tão importantes quanto a origem do aplicativo e testa tudo, desde integridade até gatilhos, procedimentos e registro.

Aiden Bell
fonte
4

Usamos integração contínua via TeamCity. Em cada check-in para o controle de origem, o banco de dados e todos os dados de teste são reconstruídos do zero, em seguida, o código e os testes de unidade são executados no código. Se você estiver usando uma ferramenta de geração de código como CodeSmith, ela também pode ser colocada em seu processo de compilação para gerar sua camada de acesso a dados nova com cada compilação, certificando-se de que todas as suas camadas "combinem" e não produzam erros devido a parâmetros SP incompatíveis ou colunas ausentes.

Cada construção tem sua própria coleção de scripts SQL que são armazenados no diretório $ project \ SQL \ no controle de origem, atribuídos a um prefixo numérico e executados em ordem. Dessa forma, estamos praticando nosso procedimento de implantação em cada build.

Dependendo da tabela de pesquisa, a maioria dos nossos valores de pesquisa também são armazenados em scripts e executados para garantir que os dados de configuração sejam os que esperamos, digamos, "reason_codes" ou "country_codes". Dessa forma, podemos fazer uma alteração nos dados de pesquisa no dev, testá-los e "promovê-los" por meio de controle de qualidade e produção, em vez de usar uma ferramenta para modificar os valores de pesquisa na produção, o que pode ser perigoso para o tempo de atividade.

Também criamos um conjunto de scripts de "rollback" que desfazem as alterações do nosso banco de dados, no caso de um build para produção dar errado. Você pode testar os scripts de rollback executando-os e, em seguida, executando novamente os testes de unidade para a versão de compilação abaixo da sua, após a execução dos scripts de implantação.

Chris McCall
fonte
4

+1 para Liquibase : LiquiBase é uma biblioteca independente de banco de dados de código aberto (LGPL) para rastrear, gerenciar e aplicar alterações de banco de dados. Ele é construído em uma premissa simples: todas as alterações do banco de dados (estrutura e dados) são armazenadas de maneira descritiva baseada em XML e verificadas no controle de origem. O bom ponto é que as alterações DML são armazenadas semanticamente, não apenas diff, para que você possa rastrear o propósito das alterações.

Ele pode ser combinado com o controle de versão GIT para uma melhor interação. Vou configurar nosso ambiente dev-prod para testá-lo.

Você também pode usar Maven, sistemas de construção Ant para construir código de produção a partir de scripts.

A desvantagem é que LiquiBase não se integra a IDE SQL difundidos e você mesmo deve fazer as operações básicas.

Além disso, você pode usar DBUnit para teste de banco de dados - esta ferramenta permite que scripts de geração de dados sejam usados ​​para testar seu ambiente de produção com limpeza posterior.

NA MINHA HUMILDE OPINIÃO:

  1. Armazene DML em arquivos para que você possa versioná-los.
  2. Automatize o processo de construção do esquema a partir do controle de origem.
  3. Para fins de teste, o desenvolvedor pode usar o banco de dados local criado a partir do controle de origem via sistema de construção + dados de teste de carga com scripts ou scripts DBUnit (do controle de origem).
  4. LiquiBase permite que você forneça uma "sequência de execução" de scripts para respeitar as dependências.
  5. Deve haver uma equipe de DBA que verifica o brunch principal com TODAS as alterações antes de usar na produção. Quero dizer, eles verificam o tronco / ramificação de outros DBA antes de se comprometerem com o tronco MASTER. Para que o master esteja sempre consistente e pronto para a produção.

Enfrentamos todos os problemas mencionados com alterações de código, fusão, reescrita em nosso banco de dados de produção de faturamento. Este tópico é ótimo para descobrir tudo isso.

zmische
fonte
3

Ao fazer "perguntas teaser", você parece estar mais interessado em uma discussão do que na opinião de alguém sobre as respostas finais. A lista de discussão ativa (> 2500 membros) agileDatabases abordou muitas dessas questões e é, na minha experiência, um fórum sofisticado e civil para esse tipo de discussão.

Glenn
fonte
Acho improvável que uma única resposta universalmente aceita possa ser alcançada. Mas eu gostaria de identificar algumas áreas comuns de acordo - e talvez reunir uma recomendação razoável. Eu definitivamente irei olhar para o fórum agileDatabases também, obrigado.
LBushkin
3

Eu basicamente concordo com todas as respostas dadas pela van . Para mais informações, minha linha de base para gerenciamento de banco de dados é a série K. Scott Allen (uma leitura obrigatória, IMHO. E a opinião de Jeff também parece).

  • Objetos de banco de dados pode sempre ser reconstruído a partir do zero com o lançamento de um único arquivo SQL (que se pode chamar outros arquivos SQL): Create.sql. Isso pode incluir a inserção de dados estáticos (listas ...).
  • Os scripts SQL são parametrizados para que nenhuma informação dependente do ambiente e / ou confidencial seja armazenada em arquivos simples.
  • Eu uso um arquivo de lote personalizado para lançamento Create.sql: Create.cmd. Seu objetivo é principalmente verificar os pré-requisitos (ferramentas, variáveis ​​de ambiente ...) e enviar parâmetros para o script SQL. Ele também pode carregar dados estáticos em massa de arquivos CSV para problemas de desempenho.
  • Normalmente, as credenciais do usuário do sistema seriam passadas como um parâmetro para o Create.cmdarquivo.

IMHO, o carregamento dinâmico de dados deve exigir outra etapa, dependendo do seu ambiente. Os desenvolvedores desejarão carregar seu banco de dados com teste, lixo ou nenhum dado, enquanto na outra extremidade os gerentes de produção desejarão carregar os dados de produção. Eu consideraria armazenar dados de teste no controle de origem também (para facilitar o teste de unidade, por exemplo).

Assim que a primeira versão do banco de dados for colocada em produção, você precisará não apenas criar scripts (principalmente para desenvolvedores), mas também atualizar scripts (com base nos mesmos princípios):

  • Deve haver uma maneira de recuperar a versão do banco de dados (eu uso um procedimento armazenado, mas uma tabela serviria também).
  • Antes de lançar uma nova versão, crio um Upgrade.sqlarquivo (que pode chamar outros) que permite a atualização da versão N-1 para a versão N (sendo N a versão que está sendo lançada). Eu armazeno este script em uma pasta chamada N-1.
  • Eu tenho um arquivo de lote que faz o upgrade: Upgrade.cmd. Ele pode recuperar a versão atual (CV) do banco de dados por meio de uma instrução SELECT simples, iniciar o Upgrade.sqlscript armazenado na CVpasta e fazer um loop até que nenhuma pasta seja encontrada. Dessa forma, você pode atualizar automaticamente de, digamos, N-3 para N.

Os problemas são:

  • É difícil comparar esquemas de banco de dados automaticamente, dependendo dos fornecedores de banco de dados. Isso pode levar a scripts de atualização incompletos.
  • Cada mudança no ambiente de produção (geralmente por DBAs para ajuste de desempenho) deve chegar ao controle de origem também. Para ter certeza disso, geralmente é possível registrar todas as modificações no banco de dados por meio de um gatilho. Este log é redefinido após cada atualização.
  • Mais idealmente, porém, as alterações iniciadas pelo DBA devem fazer parte do processo de lançamento / atualização, quando possível.

Quanto a que tipo de objetos de banco de dados você deseja ter sob controle de origem? Bem, eu diria o máximo possível, mas não mais ;-) Se você deseja criar usuários com senhas, obtenha uma senha padrão (login / login, prático para fins de teste de unidade) e faça da alteração de senha uma operação manual . Isso acontece muito com o Oracle, onde os esquemas também são usuários ...

Mac
fonte
1

Temos nosso projeto Silverlight com banco de dados MSSQL no controle de versão Git. A maneira mais fácil é ter certeza de que você tem um banco de dados reduzido (em termos de conteúdo) e fazer um despejo completo do Visual Studio. Então você pode fazer 'sqlcmd' a partir de seu script de construção para recriar o banco de dados em cada máquina de desenvolvimento.

Para implantação, isso não é possível porque os bancos de dados são muito grandes: essa é a principal razão para tê-los em um banco de dados em primeiro lugar.

Rutger Nijlunsing
fonte
1

Eu acredito fortemente que um banco de dados deve fazer parte do controle de origem e, em grande parte, do processo de construção. Se estiver no controle de origem, eu tenho as mesmas proteções de codificação ao escrever um procedimento armazenado em SQL e ao escrever uma classe em C #. Eu faço isso incluindo um diretório de scripts de banco de dados em minha árvore de origem. Este diretório de script não tem necessariamente um arquivo para um objeto no banco de dados. Isso seria um pé no saco! Eu desenvolvo no meu banco de dados apenas como faria no meu projeto de código. Então, quando estou pronto para fazer o check-in, faço uma comparação entre a última versão do meu banco de dados e a atual em que estou trabalhando. Eu uso o SQL Compare para isso e ele gera um script de todas as mudanças. Este script é então salvo em meu diretório db_update com uma convenção de nomenclatura específica 1234_TasksCompletedInThisIteration em que o número é o próximo número no conjunto de scripts já existentes e o nome descreve o que está sendo feito neste check-in. Eu faço isso desta forma porque parte do meu processo de construção eu começo com um novo banco de dados que é então construído programaticamente usando os scripts neste diretório. Eu escrevi uma tarefa NAnt personalizada que itera por meio de cada script que executa seu conteúdo no banco de dados vazio. Obviamente, se eu precisar de alguns dados para entrar no banco de dados, também tenho scripts de inserção de dados. Isso tem muitos benefícios também. Um, todas as minhas coisas são versionadas. Dois, cada construção é uma nova construção, o que significa que não haverá qualquer coisa sorrateira entrando no meu processo de desenvolvimento (como dados sujos que causam estranhezas no sistema). Terceiro, quando um novo cara é adicionado à equipe de desenvolvimento, ele simplesmente precisa obter o mais recente e seu desenvolvedor local é criado para ele imediatamente. Quatro, posso executar casos de teste (não chamei de "teste de unidade"!) Em meu banco de dados, pois o estado do banco de dados é redefinido com cada compilação (o que significa que posso testar meus repositórios sem me preocupar em adicionar dados de teste ao db).

Isso não é para todos.

Isso não é para todos os projetos. Eu costumo trabalhar em projetos verdes, o que me permite essa comodidade!

Andrew Siemer
fonte
Fico feliz em saber que você está usando o SQL Compare como parte do seu ciclo de vida de desenvolvimento de banco de dados. Achamos que podemos ter melhorado a facilidade de os desenvolvedores obterem novas alterações. Verifique o SQL Source Control. Isso funciona lado a lado com o SQL Compare para facilitar a colaboração do desenvolvedor, além de permitir que você mantenha a fonte de seus objetos de esquema controlada (desde que esteja usando SVN ou TFS). red-gate.com/products/sql_source_control/index.htm
David Atkinson
1

Em vez de entrar em argumentos de torre branca, aqui está uma solução que funcionou muito bem para mim em problemas do mundo real.

Construir um banco de dados do zero pode ser resumido como o gerenciamento de scripts sql.

DBdeploy é uma ferramenta que verifica o estado atual de um banco de dados - por exemplo, quais scripts foram executados anteriormente nele, quais scripts estão disponíveis para serem executados e, portanto, quais scripts são necessários para serem executados.

Em seguida, ele agrupará todos os scripts necessários e os executará. Em seguida, ele registra quais scripts foram executados.

Não é a ferramenta mais bonita nem a mais complexa - mas com um gerenciamento cuidadoso pode funcionar muito bem. É open source e facilmente extensível. Depois que a execução dos scripts é bem tratada, é fácil adicionar alguns componentes extras, como um script de shell que verifica os scripts mais recentes e executa o dbdeploy em uma instância específica.

Veja uma boa introdução aqui:

http://code.google.com/p/dbdeploy/wiki/GettingStarted

Pablojim
fonte
0

Você pode descobrir que a Liquibase lida com muito do que você está procurando.

David Plumpton
fonte
0

Cada desenvolvedor deve ter seu próprio banco de dados local e usar o controle do código-fonte para publicar para a equipe. Minha solução está aqui: http://dbsourcetools.codeplex.com/ Divirta-se, - Nathan

Nathan Rozentals
fonte