Ao fazer uma instrução ALTER TABLE no MySQL, toda a tabela é bloqueada para leitura (permitindo leituras simultâneas, mas proibindo gravações simultâneas) durante a instrução. Se for uma mesa grande, as instruções INSERT ou UPDATE podem ser bloqueadas por muuuuito tempo. Existe uma maneira de fazer uma "alteração quente", como adicionar uma coluna de forma que a tabela ainda seja atualizável durante o processo?
Em geral, estou interessado em uma solução para MySQL, mas estaria interessado em outro RDBMS se o MySQL não pudesse fazer isso.
Para esclarecer, meu objetivo é simplesmente evitar o tempo de inatividade quando um novo recurso que requer uma coluna de tabela extra é colocado em produção. Qualquer esquema de banco de dados vai mudar ao longo do tempo, isso é apenas um fato da vida. Não vejo por que devemos aceitar que essas mudanças resultem inevitavelmente em tempo de inatividade; isso é apenas fraco.
fonte
Respostas:
A única outra opção é fazer manualmente o que muitos sistemas RDBMS fazem de qualquer maneira ...
- Criar uma nova tabela
Você pode então copiar o conteúdo da tabela antiga sobre um pedaço de cada vez. Embora sempre seja cauteloso com qualquer INSERT / UPDATE / DELETE na tabela de origem. (Pode ser gerenciado por um gatilho. Embora isso cause uma lentidão, não é um bloqueio ...)
Quando terminar, altere o nome da tabela de origem e, em seguida, altere o nome da nova tabela. De preferência em uma transação.
Quando terminar, recompile todos os procedimentos armazenados, etc. que usam essa tabela. Os planos de execução provavelmente não serão mais válidos.
EDITAR:
Alguns comentários foram feitos sobre esta limitação ser um pouco pobre. Então eu pensei em colocar uma nova perspectiva sobre isso para mostrar por que é assim ...
fonte
Percona faz uma ferramenta chamada pt-online-schema-change que permite que isso seja feito.
Essencialmente, faz uma cópia da tabela e modifica a nova tabela. Para manter a nova tabela sincronizada com a original, ela usa gatilhos para atualizar. Isso permite que a tabela original seja acessada enquanto a nova tabela é preparada em segundo plano.
Isso é semelhante ao método sugerido pelo Dems acima, mas de maneira automatizada.
Algumas de suas ferramentas têm uma curva de aprendizado, ou seja, conectar-se ao banco de dados, mas uma vez que você tenha feito isso, elas são ótimas ferramentas.
Ex:
fonte
Esta questão de 2009. Agora o MySQL oferece uma solução:
DDL online (linguagem de definição de dados)
Ele permite que você ajuste o equilíbrio entre desempenho e simultaneidade durante a operação DDL, escolhendo se deseja bloquear o acesso à tabela inteiramente (LOCK = cláusula EXCLUSIVE), permitir consultas, mas não DML (LOCK = cláusula SHARED) ou permitir consulta completa e DML acesso à tabela (cláusula LOCK = NONE). Quando você omite a cláusula LOCK ou especifica LOCK = DEFAULT, o MySQL permite o máximo de simultaneidade possível, dependendo do tipo de operação.
Executar mudanças no local onde possível, em vez de criar uma nova cópia da tabela, evita aumentos temporários no uso de espaço em disco e sobrecarga de E / S associada à cópia da tabela e reconstrução de índices secundários.
consulte o Manual de Referência do MySQL 5.6 -> InnoDB e DDL online para obter mais informações.
Parece que o DDL online também está disponível no MariaDB
MariaDB KB sobre ALTER TABLE
fonte
Consulte a ferramenta de mudança de esquema online do Facebook.
http://www.facebook.com/notes/mysql-at-facebook/online-schema-change-for-mysql/430801045932
Não para os fracos de coração; mas fará o trabalho.
fonte
Eu recomendo Postgres se essa for uma opção. Com o postgres, essencialmente não há tempo de inatividade com os seguintes procedimentos:
Outro ótimo recurso é que a maioria das instruções DDL são transacionais, então você pode fazer uma migração inteira dentro de uma transação SQL e, se algo der errado, tudo será revertido.
Eu escrevi isso um pouco atrás, talvez possa esclarecer melhor os outros méritos.
fonte
Como você perguntou sobre outros bancos de dados, aqui estão algumas informações sobre o Oracle.
Adicionar uma coluna NULL a uma tabela Oracle é uma operação muito rápida, pois apenas atualiza o dicionário de dados. Isso mantém um bloqueio exclusivo na mesa por um período muito curto de tempo. No entanto, isso invalidará quaisquer procedimentos armazenados, visualizações, gatilhos, etc. Depedant. Eles serão recompilados automaticamente.
A partir daí, se necessário, você pode criar um índice usando a cláusula ONLINE. Novamente, apenas bloqueios de dicionário de dados muito curtos. Ele lerá toda a tabela procurando coisas para indexar, mas não bloqueará ninguém enquanto faz isso.
Se precisar adicionar uma chave estrangeira, você pode fazer isso e fazer com que o Oracle confie em você de que os dados estão corretos. Caso contrário, ele precisa ler toda a tabela e validar todos os valores que podem ser lentos (crie seu índice primeiro).
Se você precisar colocar um valor padrão ou calculado em cada linha da nova coluna, você precisará executar uma atualização massiva ou talvez um pequeno programa utilitário que preencha os novos dados. Isso pode ser lento, especialmente se as linhas ficarem muito maiores e não couberem mais em seus blocos. O bloqueio pode ser gerenciado durante este processo. Como o antigo versino de seu aplicativo, que ainda está em execução, não conhece esta coluna, você pode precisar de um gatilho sorrateiro ou para especificar um padrão.
A partir daí, você pode fazer um switcharoo em seus servidores de aplicativos para a nova versão do código e ele continuará em execução. Solte seu gatilho sorrateiro.
Alternativamente, você pode usar DBMS_REDEFINITION, que é uma caixa preta projetada para fazer esse tipo de coisa.
Tudo isso é tão trabalhoso para testar, etc, que apenas temos uma interrupção no início da manhã de domingo sempre que lançamos uma versão principal.
fonte
Se você não pode permitir o tempo de inatividade do seu banco de dados ao fazer atualizações de aplicativos, deve considerar a manutenção de um cluster de dois nós para alta disponibilidade. Com uma configuração de replicação simples, você pode fazer mudanças estruturais quase totalmente online como a que você sugere:
Nem sempre é fácil, mas funciona, geralmente com 0 tempo de inatividade! O segundo nó não precisa ser apenas um nó passivo, ele pode ser usado para testar, fazer estatísticas ou como um nó de fallback. Se você não tiver infraestrutura, a replicação pode ser configurada em uma única máquina (com duas instâncias do MySQL).
fonte
Não. Se você estiver usando tabelas MyISAM, para meu melhor entendimento, eles só fazem bloqueios de tabela - não há bloqueios de registro, eles apenas tentam manter tudo hiper-rápido por meio da simplicidade. (Outras tabelas do MySQL operam de maneira diferente.) Em qualquer caso, você pode copiar a tabela para outra tabela, alterá-la e, em seguida, trocá-las, atualizando as diferenças.
Essa é uma alteração tão grande que duvido que algum DBMS a suporte. É considerado uma vantagem poder fazer isso com os dados da tabela em primeiro lugar.
fonte
Solução temporária...
Outra solução poderia ser adicionar outra tabela com a chave primária da tabela original, junto com sua nova coluna.
Preencha sua chave primária na nova tabela e preencha valores para a nova coluna em sua nova tabela e modifique sua consulta para unir esta tabela para operações selecionadas e você também precisa inserir, atualizar separadamente para este valor de coluna.
Quando você consegue obter um tempo de inatividade, pode alterar a tabela original, modificar suas consultas DML e descartar sua nova tabela criada anteriormente
Caso contrário, você pode ir para o método de clustering, replicação, ferramenta pt-online-schema de percona
fonte
Usando o plugin Innodb, as instruções ALTER TABLE que apenas adicionam ou descartam índices secundários podem ser feitas "rapidamente", ou seja, sem reconstruir a tabela.
De um modo geral, entretanto, no MySQL, qualquer ALTER TABLE envolve a reconstrução de toda a tabela, o que pode levar muito tempo (ou seja, se a tabela contiver uma quantidade útil de dados).
Você realmente precisa projetar seu aplicativo de forma que as instruções ALTER TABLE não precisem ser feitas regularmente; você certamente não deseja que nenhum ALTER TABLE seja executado durante a execução normal do aplicativo, a menos que esteja preparado para esperar ou alterando tabelas minúsculas.
fonte
Eu recomendaria uma de duas abordagens:
Projete suas tabelas de banco de dados com as possíveis mudanças em mente. Por exemplo, trabalhei com sistemas de gerenciamento de conteúdo, que alteram campos de dados no conteúdo regularmente. Em vez de construir a estrutura física do banco de dados para corresponder aos requisitos iniciais do campo CMS, é muito melhor construir uma estrutura flexível. Nesse caso, usando um campo de texto blob (varchar (max) por exemplo) para manter dados XML flexíveis. Isso torna as mudanças estruturais muito menos frequentes. Mudanças estruturais podem ser caras, portanto, há um benefício no custo aqui também.
Tem tempo de manutenção do sistema. O sistema fica offline durante as mudanças (mensalmente, etc), e as mudanças são programadas durante o horário do dia com menos tráfego (3 a 5 da manhã, por exemplo). As mudanças são preparadas antes do lançamento da produção, então você terá uma boa estimativa de janela fixa de tempo de inatividade.
2a. Ter servidores redundantes, para que quando o sistema ficar inativo, todo o site não fique inativo. Isso permitiria a você "lançar" suas atualizações de forma escalonada, sem tirar todo o site do ar.
As opções 2 e 2a podem não ser viáveis; eles tendem a ser apenas para sites / operações maiores. No entanto, são opções válidas e usei pessoalmente todas as opções apresentadas aqui.
fonte
Se alguém ainda estiver lendo isso ou vier aqui, este é o grande benefício de usar um sistema de banco de dados NoSQL como o mongodb. Tive o mesmo problema ao lidar com a alteração da tabela para adicionar colunas para recursos adicionais ou índices em uma grande tabela com milhões de linhas e altas gravações. Isso acabaria travando por um longo tempo, então fazer isso no banco de dados LIVE frustraria nossos usuários. Em mesas pequenas, você pode se safar.
Odeio o fato de termos que "projetar nossas tabelas para evitar alterá-las". Só não acho que isso funcione no mundo dos sites de hoje. Você não pode prever como as pessoas usarão seu software, por isso você muda rapidamente as coisas com base no feedback do usuário. Com mongodb, você pode adicionar "colunas" à vontade, sem tempo de inatividade. Você nem mesmo os adiciona, apenas insere dados com novas colunas e isso faz isso automaticamente.
Vale a pena conferir: www.mongodb.com
fonte
Em geral, a resposta será "Não". Você está mudando a estrutura da tabela, o que potencialmente exigirá muitas atualizações "e eu definitivamente concordo com isso. Se você espera fazer isso com frequência, então vou oferecer uma alternativa para colunas" fictícias "- use
VIEW
s em vez de tabelas paraSELECT
inserir dados. IIRC, alterar a definição de uma visão é relativamente leve e a indireção por meio de uma visão é feita quando o plano de consulta é compilado. A despesa é que você teria que adicionar a coluna a uma nova tabela e fazer o visualizarJOIN
na coluna.Claro que isso só funciona se você puder usar chaves estrangeiras para executar o cascateamento de exclusões e outros enfeites. O outro bônus é que você pode criar uma nova tabela contendo uma combinação de dados e apontar a visão para ela sem perturbar o uso do cliente.
Apenas um pensamento.
fonte
A diferença entre o Postgres e o MySQL a esse respeito é que no Postgres ele não recria uma tabela, mas modifica o dicionário de dados que é semelhante ao Oracle. Portanto, a operação é rápida, embora ainda exija a alocação de um bloqueio de tabela DDL exclusivo por um período muito curto, conforme afirmado acima por outros.
No MySQL, a operação copiará os dados para uma nova tabela enquanto bloqueia as transações, o que era o principal problema para os DBAs do MySQL antes da v. 5.6.
A boa notícia é que, desde o lançamento do MySQL 5.6, a restrição foi praticamente suspensa e agora você pode desfrutar do verdadeiro poder do banco de dados MYSQL.
fonte
Como SeanDowney mencionou,
pt-online-schema-change
é uma das melhores ferramentas para fazer o que você descreveu na pergunta aqui. Recentemente, fiz muitas alterações de esquema em um banco de dados ativo e tudo correu muito bem. Você pode ler mais sobre isso na minha postagem do blog aqui: http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/ .fonte
Você definitivamente deveria tentar
pt-online-schema-change
. Tenho usado essa ferramenta para fazer migrações no AWS RDS com vários escravos e tem funcionado muito bem para mim. Escrevi um post elaborado no blog sobre como fazer isso que pode ser útil para você.Blog: http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/
fonte
As colunas fictícias são uma boa ideia se você puder prever seu tipo (e torná-las anuláveis). Verifique como seu mecanismo de armazenamento lida com nulos.
O MyISAM irá bloquear tudo se você sequer mencionar o nome de uma mesa de passagem, no telefone, no aeroporto. Simplesmente faz isso ...
Dito isso, os bloqueios não são realmente um grande negócio; contanto que você não esteja tentando adicionar um valor padrão para a nova coluna a cada linha, mas deixe-o como nulo, e seu mecanismo de armazenamento seja inteligente o suficiente para não ir gravá-lo, você deve estar ok com um bloqueio que é apenas mantida por tempo suficiente para atualizar os metadados. Se você tentar escrever um novo valor, bem, você está frito.
fonte
TokuDB pode adicionar / eliminar colunas e adicionar índices "quentes", a tabela está totalmente disponível durante todo o processo. Ele está disponível em www.tokutek.com
fonte
Na verdade não.
Afinal, você ESTÁ alterando a estrutura subjacente da tabela, e essa é uma informação muito importante para o sistema subjacente. Você também (provavelmente) está movendo muitos dos dados no disco.
Se você planeja fazer muito isso, é melhor simplesmente preencher a tabela com colunas "fictícias" que estão disponíveis para uso futuro.
fonte