AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 440
Accepted
Hendrik Brummermann
Hendrik Brummermann
Asked: 2011-01-10 03:20:03 +0800 CST2011-01-10 03:20:03 +0800 CST 2011-01-10 03:20:03 +0800 CST

Como converter uma tabela de 66.862.521 linhas de MyISAM para InnoDB sem ficar offline por várias horas?

  • 772

é possível (e como) converter uma enorme tabela MyISAM em InnoDB sem colocar o aplicativo offline. É necessário inserir algumas linhas nessa tabela a cada segundo, mas é possível suspendê-la por cerca de 2 minutos.

Obviamente, ALTER TABLE ... engine=innodb não funcionará. Portanto, eu tinha o plano de criar uma nova tabela com o mecanismo innodb e copiar o conteúdo para ela. E no final, suspenda o thread de log do aplicativo e RENAME TABLE.

Infelizmente, mesmo fazendo a cópia em pequenos lotes de 100 linhas gera um atraso significativo após algum tempo.

Editar : as linhas existentes nunca são alteradas, esta tabela é usada para registro.

mysql innodb
  • 4 4 respostas
  • 1689 Views

4 respostas

  • Voted
  1. Best Answer
    Derek Downey
    2011-01-10T13:55:52+08:002011-01-10T13:55:52+08:00

    Crie uma configuração Master-Master da seguinte forma:

    • Criar segundo mestre, MasterB
    • MasterB atua como escravo paralogTable
    • Criar logTable_newcomo innodb
    • Execute INSERT INTO logTable_new SELECT * FROM logTable(psuedocode) no MasterB, que envia a replicação para o MasterA
    • Quando logTable_newno MasterA terminar a sincronização, troque as tabelas
    • 15
  2. Joe
    2011-01-10T09:05:56+08:002011-01-10T09:05:56+08:00

    Dada a restrição de:

    Não me importo se as conversas demoram alguns dias ou semanas. Mas deve funcionar em segundo plano sem exigir tempo de inatividade do aplicativo e sem criar lag perceptível

    Ao fazer o registro, se você tiver uma boa maneira de definir um marcador para poder dizer o que você inicia o processo, para poder reaplicar os registros ou gravar os registros em um arquivo de texto para você pode ingeri-los mais tarde comLOAD DATA INFILE

    Parte do problema é que escrever em lotes menores significa que os índices precisam ser recalculados repetidamente; é melhor executar tudo de uma vez, mas isso pode causar algum atraso 'perceptível' no sistema .. mas você não precisa fazer isso no servidor de produção.

    1. Pause o registro ou defina algum marcador para que você possa reaplicar os registros a partir deste ponto mais tarde.
    2. Copie sua tabela MyISM para outro sistema
    3. No outro sistema, crie uma tabela InnoDB com um nome diferente e migre os dados (pode até ser mais rápido despejá-los e usar LOAD DATA INFILE)
    4. Copie a tabela InnoDB de volta para o sistema original
    5. Defina outro marcador para o registro.
    6. Reaplique todos os logs à nova tabela entre os dois últimos marcadores.
    7. (repita as etapas 5 e 6 se a etapa 6 demorar mais de um minuto ou mais, até que sejam apenas alguns segundos)
    8. Troque as tabelas (renomeie a antiga para table_BACKUP, a nova sob o nome da antiga)
    9. Recupere os logs desde o último marcador.
    • 10
  3. David Spillett
    2011-01-10T05:30:14+08:002011-01-10T05:30:14+08:00

    Infelizmente, mesmo fazendo a cópia em pequenos lotes de 100 linhas gera um atraso significativo após algum tempo.

    Você está adicionando algum atraso entre cada lote ou apenas agrupando as atualizações e executando cada lote diretamente após o anterior?

    Nesse caso, tente fazer o script da conversão em seu idioma favorito com algo como:

    repeat
        copy oldest 100 rows that haven't been copied yet to new table
        sleep for as long as that update took
    until there are <100 rows unprocessed
    stop logging service
    move the last few rows
    rename tables
    restart logging
    delete the old table when you are sure the conversion has worked
    

    Isso deve garantir que a conversão não ocupe mais do que metade da capacidade do seu servidor, mesmo permitindo diferenças na carga imposta conforme o uso do sistema varia com o tempo.

    Ou se você quiser usar o máximo de tempo possível quando o serviço estiver relativamente ocioso, mas recuar (possivelmente pausando por um longo período de tempo) quando o banco de dados precisar fazer algum trabalho para seus usuários, substitua sleep for as long as the update tookpor if the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>. Isso significa que ele pode avançar em tempos de silêncio, mas fará uma pausa completa quando o servidor estiver ocupado executando sua carga de trabalho normal. A determinação da carga dependerá do seu sistema operacional - no Linux e semelhante, o valor médio de carga de 1 minuto /proc/loadavgou a saída de uptimedeve funcionar. <lower measure>e <upper measure>pode ser o mesmo valor, embora seja comum em controles como este ter uma diferença para que seu processo não continue iniciando e parando imediatamente devido ao seu próprio reinício ter influência na medida de carga.

    É claro que isso não funcionaria para tabelas onde as linhas antigas podem ser modificadas, mas funcionará bem para uma tabela de log como a que você descreveu.

    Você vai querer ignorar a sabedoria usual de criar índices depois de preencher a nova tabela neste caso. Embora isso seja realmente mais eficiente quando você deseja que as coisas sejam o mais rápido possível (que se dane o efeito no restante do sistema), neste caso você não deseja o grande excesso de carga no final do processo, pois o os índices são criados completamente de uma só vez, pois esse é um processo que você não pode pausar quando as coisas ficam ocupadas.

    • 9
  4. Riedsio
    2011-01-14T12:55:05+08:002011-01-14T12:55:05+08:00

    Algo assim funcionaria?

    1. Pause o log (para que o $auto_incrementna sua tabela de log mytable não mude).
    2. Observe o $auto_incrementvalor usando SHOW TABLE STATUS LIKE 'mytable'.
    3. CREATE TABLE mytable_new LIKE mytable
    4. ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
    5. RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
    6. Habilite o log novamente. A tabela Innodb agora começará a ser preenchida.
    7. INSERT INTO mytable SELECT * FROM mytable_old.

    Você pode executar a etapa 7 em lotes ou em uma instrução, pois não deve bloquear o registro normal.

    • 4

relate perguntas

  • Existem ferramentas de benchmarking do MySQL? [fechado]

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

  • Quando é o momento certo para usar o MariaDB em vez do MySQL e por quê?

  • Como um grupo pode rastrear alterações no esquema do banco de dados?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como você mostra o SQL em execução em um banco de dados Oracle?

    • 2 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Posso ver Consultas Históricas executadas em um banco de dados SQL Server?

    • 6 respostas
  • Marko Smith

    Como uso currval() no PostgreSQL para obter o último id inserido?

    • 10 respostas
  • Marko Smith

    Como executar o psql no Mac OS X?

    • 11 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Marko Smith

    Passando parâmetros de array para um procedimento armazenado

    • 12 respostas
  • Martin Hope
    Manuel Leduc Restrição exclusiva de várias colunas do PostgreSQL e valores NULL 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler Quando uma chave primária deve ser declarada sem cluster? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - Qual é melhor como chave primária? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick Como posso otimizar um mysqldump de um banco de dados grande? 2011-01-04 13:13:48 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve