Como reduzir / limpar o arquivo ibdata1 no MySQL

561

Estou usando o MySQL no localhost como uma "ferramenta de consulta" para executar estatísticas no R, ou seja, toda vez que executo um script R, crio um novo banco de dados (A), crio uma nova tabela (B), importo os dados para B , envie uma consulta para obter o que eu preciso e, em seguida, solto B e solto A.

Está funcionando bem para mim, mas percebo que o tamanho do arquivo ibdata está aumentando rapidamente, não guardei nada no MySQL, mas o arquivo ibdata1 já ultrapassava 100 MB.

Estou usando a configuração MySQL mais ou menos padrão para a instalação. Existe uma maneira de reduzir / limpar automaticamente o arquivo ibdata1 após um período fixo de tempo?

lokheart
fonte

Respostas:

778

Isso ibdata1não está diminuindo, é um recurso particularmente irritante do MySQL. Na ibdata1verdade, o arquivo não pode ser reduzido a menos que você exclua todos os bancos de dados, remova os arquivos e recarregue um despejo.

Mas você pode configurar o MySQL para que cada tabela, incluindo seus índices, seja armazenada como um arquivo separado. Dessa forma ibdata1, não crescerá tão grande. De acordo com o comentário de Bill Karwin, isso é ativado por padrão a partir da versão 5.6.6 do MySQL.

Foi há um tempo atrás que eu fiz isso. No entanto, para configurar o servidor para usar arquivos separados para cada tabela, é necessário alterar my.cnfpara permitir isso:

[mysqld]
innodb_file_per_table=1

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

Como você deseja recuperar o espaço, na ibdata1verdade você precisa excluir o arquivo:

  1. Fazer um mysqldumpde todos os bancos de dados, procedimentos, gatilhos etc , exceto o mysqle performance_schemabancos de dados
  2. Descarte todos os bancos de dados, exceto os 2 bancos de dados acima
  3. Pare o mysql
  4. Excluir ibdata1e ib_logarquivos
  5. Inicie o mysql
  6. Restaurar do despejo

Quando você inicia o MySQL na etapa 5, os arquivos ibdata1e ib_logserão recriados.

Agora você está pronto para ir. Quando você cria um novo banco de dados para análise, as tabelas serão localizadas em ibd*arquivos separados , e não em ibdata1. Como você geralmente descarta o banco de dados logo depois, os ibd*arquivos serão excluídos.

http://dev.mysql.com/doc/refman/5.1/en/drop-database.html

Você provavelmente já viu isso:
http://bugs.mysql.com/bug.php?id=1341

Ao usar o comando ALTER TABLE <tablename> ENGINE=innodbou OPTIMIZE TABLE <tablename>se pode extrair dados e páginas de índice de ibdata1 para arquivos separados. No entanto, ibdata1 não será reduzido a menos que você execute as etapas acima.

Em relação ao information_schema, isso não é necessário nem possível cair. Na verdade, é apenas um monte de visualizações somente leitura, não tabelas. E não há arquivos associados a eles, nem mesmo um diretório de banco de dados. O informations_schemaestá usando o mecanismo db de memória e é descartado e regenerado após a parada / reinicialização do mysqld. Consulte https://dev.mysql.com/doc/refman/5.7/en/information-schema.html .

John P
fonte
16
@JordanMagnuson Não se preocupe em deixar o information_schema. Na verdade, é apenas um monte de visualizações somente leitura, não tabelas. E não há arquivos associados a eles. Não há nem um diretório para o banco de dados. O informations_schema está usando o mecanismo db de memória e é descartado e regenerado após a parada / reinicialização do mysqld. Consulte dev.mysql.com/doc/refman/5.5/en/information-schema.html . Em relação ao performance_schema, eu mesmo não usei esse esquema.
John P
4
Não sei se isso é algo recente, mas uma vez que a opção innodb_file_per_table esteja ativada, você pode simplesmente executar "ALTER TABLE <tablename> ENGINE = InnoDB" (mesmo que já seja o InnoDB) e moverá a tabela para seu arquivo individual . Não há necessidade de descartar bancos de dados e tal.
CR.
3
+1 no FWIW, o MySQL 5.6 é ativado innodb_file_per_tablepor padrão.
Bill Karwin
3
Sim, espera-se que o ibdata1 esteja presente junto com os outros arquivos. O arquivo ibdata1 ainda conterá metadados sobre tabelas, o log de desfazer e buffers.
John P
1
Eu fiquei sem espaço no meu servidor por causa do arquivo ibdata1, então não posso nem despejar os bancos de dados. Seria o mesmo apenas mover os arquivos em / var / lib / mysql (exceto "mysql", "ibdata1", "ib_logfile0" e "ib_logfile1") e siga as etapas? Veja stackoverflow.com/questions/2482491/…
Sophivorus
47

Adicionando à resposta de John P ,

Para um sistema linux, as etapas 1 a 6 podem ser realizadas com estes comandos:

  1. mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql
  2. DROP DATABASE [database_name];
  3. sudo /etc/init.d/mysqld stop
  4. sudo rm /var/lib/mysql/ibdata1
    sudo rm /var/lib/mysql/ib_logfile (e exclua outros ib_logfiles que possam ser nomeados ib_logfile0, ib_logfile1etc ...)
  5. sudo /etc/init.d/mysqld start
  6. create database [database_name];
  7. mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql

Aviso: estas instruções farão com que você perca outros bancos de dados se houver outros bancos de dados nessa instância do mysql. Verifique se as etapas 1,2 e 6,7 foram modificadas para cobrir todos os bancos de dados que você deseja manter.

Vinay Vemula
fonte
6
Você precisa repetir 1,2 e 6 para cada banco de dados que possui tabelas do InnoDB.
Marquês de Lorne
4
Você precisa de mais algumas etapas entre os itens 5 e 6. Você precisa recriar o banco de dados e reatribuir permissões. Assim, a partir de comando mysql client pronta create database database_name;e depoisgrant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
fred
1
@fred Não precisei conceder privilégios ao fazer isso. Possivelmente porque eu recriei o banco de dados com o mesmo nome?
crmpicco
2
Para digitar a senha em um Password:prompt (que é uma prática mais segura), basta colocar -psem nenhuma senha real.
ADTC 25/10
Gatilhos, eventos e rotinas / funções não são descartados, a menos que você diga ao mysqldump para fazer isso. Adicione as rotinas --triggers, --events e -, se algum dos seus bancos de dados as contiver. Além disso, basta despejar com --all-database para despejar todos os bancos de dados de uma só vez, em vez de um por um.
Friek 6/06/19
34

Quando você exclui tabelas innodb, o MySQL não libera o espaço dentro do arquivo ibdata, é por isso que continua crescendo. Esses arquivos quase nunca encolhem.

Como reduzir um arquivo ibdata existente:

http://dev.mysql.com/doc/refman/5.5/en/innodb-resize-system-tablespace.html

Você pode criar um script e agendar o script para execução após um período fixo de tempo, mas para a instalação descrita acima, parece que vários espaços de tabela são uma solução mais fácil.

Se você usar a opção de configuração innodb_file_per_table, crie vários espaços de tabela. Ou seja, o MySQL cria arquivos separados para cada tabela em vez de um arquivo compartilhado. Esses arquivos separados são armazenados no diretório do banco de dados e são excluídos quando você exclui esse banco de dados. Isso deve remover a necessidade de reduzir / remover arquivos ibdata no seu caso.

Mais informações sobre vários espaços de tabela:

http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html

titanoboa
fonte
primeiro link quebrado, correspondência mais próxima que eu pude encontrar: dev.mysql.com/doc/refman/5.5/en/…
BlackICE
14

Se você usa o mecanismo de armazenamento InnoDB para (algumas de) suas tabelas MySQL, provavelmente já encontrou um problema com sua configuração padrão. Como você deve ter notado no diretório de dados do seu MySQL (no Debian / Ubuntu - / var / lib / mysql) existe um arquivo chamado 'ibdata1'. Ele contém quase todos os dados do InnoDB (não é um log de transações) da instância do MySQL e pode ficar muito grande. Por padrão, esse arquivo tem um tamanho inicial de 10Mb e se estende automaticamente. Infelizmente, por design, os arquivos de dados do InnoDB não podem ser reduzidos. É por isso que DELETEs, TRUNCATEs, DROPs, etc. não recuperam o espaço usado pelo arquivo.

Eu acho que você pode encontrar uma boa explicação e solução lá:

http://vdachev.net/2007/02/22/mysql-reducing-ibdata1/

Vik
fonte
11

Script rapidamente o procedimento da resposta aceita no bash:

#!/usr/bin/env bash
DATABASES="$(mysql -e 'show databases \G' | grep "^Database" | grep -v '^Database: mysql$\|^Database: binlog$\|^Database: performance_schema\|^Database: information_schema' | sed 's/^Database: //g')"
mysqldump --databases $DATABASES -r alldatabases.sql && echo "$DATABASES" | while read -r DB; do
    mysql -e "drop database \`$DB\`"
done && \
    /etc/init.d/mysql stop && \
    find /var/lib/mysql -maxdepth 1 -type f \( -name 'ibdata1' -or -name 'ib_logfile*' \) -delete && \
    /etc/init.d/mysql start && \
    mysql < alldatabases.sql && \
    rm -f alldatabases.sql

Salvar como purge_binlogs.she executar como root.

Exclui mysql, information_schema, performance_schema(e binlogdiretório).

Supõe que você tenha credenciais de administrador /root/.my.cnfe que seu banco de dados esteja no /var/lib/mysqldiretório padrão .

Você também pode limpar os logs binários depois de executar este script para recuperar mais espaço em disco com:

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;
Pierre-Alexis de Solminihac
fonte
Ainda não sei por que, mas hoje algumas das minhas tabelas do InnoDB foram corrompidas durante um processo semelhante; portanto, não as removia alldatabases.sqlantes de verificar novamente se todas as tabelas estão em boas condições. Quanto a algumas melhorias: defina innodb_fast_shutdown=0antes do desligamento, defina autocommit=0antes de importar o arquivo SQL, execute COMMITe defina autocommit=1após a importação do arquivo SQL, use mysqlcheck --all-databasesantes de excluir o backup.
Victor Victor
6

Se seu objetivo é monitorar o espaço livre do MySQL e você não pode parar o MySQL para reduzir seu arquivo ibdata, faça-o através dos comandos de status da tabela. Exemplo:

MySQL> 5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $20}'

MySQL <5.1.24:

mysqlshow --status myInnodbDatabase myTable | awk '{print $35}'

Em seguida, compare esse valor com seu arquivo ibdata:

du -b ibdata1

Fonte: http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html

Cyno
fonte
4

Em uma nova versão do mysql-server, as receitas acima esmagarão o banco de dados "mysql". Na versão antiga, funciona. Em algumas tabelas novas, alterna para o tipo de tabela INNODB e, ao fazer isso, você os danifica. A maneira mais fácil é:

  • despejar todos os seus bancos de dados
  • desinstale o mysql-server,
  • adicionar permaneceu my.cnf:
    [mysqld]
    innodb_file_per_table=1
  • apague tudo em / var / lib / mysql
  • instale o mysql-server
  • restaurar usuários e bancos de dados
chave de boca ajustável
fonte
1

Como já observado, você não pode reduzir o ibdata1 (para fazer isso, é necessário despejar e reconstruir), mas também não há necessidade real.

Usando o autoextend (provavelmente a configuração de tamanho mais comum), ibdata1 pré-aloca o armazenamento, aumentando cada vez que está quase cheio. Isso torna as gravações mais rápidas, pois o espaço já está alocado.

Quando você exclui os dados, eles não diminuem, mas o espaço dentro do arquivo é marcado como não utilizado. Agora, quando você inserir novos dados, eles reutilizarão o espaço vazio no arquivo antes de aumentar o arquivo.

Portanto, ele continuará a crescer se você realmente precisar desses dados. A menos que você realmente precise de espaço para outro aplicativo, provavelmente não há razão para reduzi-lo.

steveayre
fonte
66
Eu acho que você é um pouco desdenhoso da necessidade de liberar espaço.
drewish
2
Eu tenho uma partição 60Gig Solid State. Fico sem espaço rapidamente, pois trabalho com bancos de dados de 4 + gig. Eu estou olhando para mover mysql para outra partição em breve, mas esta questão e é respostas vão me ajudar nesse meio tempo
NullVoxPopuli
3
Obrigado por esta resposta, é muito útil. Limpei algumas tabelas dos dados herdados ... é bom saber que o tamanho do disco não aumentará novamente tão cedo.
Brad
1
Eu tenho um arquivo ibdata1 de 500G - mas quase todos os dados armazenados nele agora são armazenados em arquivos por banco de dados. Eu preciso muito diminuir esse colossal desperdício de espaço!
frankster
2
Bobagem completa! Um arquivo que fica inchado precisa ser aparado, esteja você ficando sem espaço ou não . Eu chamaria isso de storage leak.
ADTC 25/10