Eu resolvi isso no StackOverflow em outubro de 2010 .
Lembre-se do arquivo mais ocupado da infraestrutura do InnoDB: / var / lib / mysql / ibdata1
Esse arquivo normalmente abriga quatro tipos de informações
- Dados da tabela
- Índices de tabela
- Dados MVCC (controle de simultaneidade de várias versões)
- Metadados da tabela (lista de IDs do espaço de tabela)
A execução OPTIMIZE TABLE
em uma tabela do InnoDB armazenada no ibdata1 faz duas coisas:
- Torna os dados e índices da tabela contíguos dentro do ibdata1, tornando mais rápido o acesso
- Faz ibdata1 crescer porque os dados contíguos e as páginas de índice são anexados a ibdata1
Embora você possa segregar dados da tabela e índices da tabela do ibdata1 e gerenciá-los independentemente usando innodb_file_per_table , a grande quantidade de espaço em disco no ibdata1 simplesmente não desaparece e não pode ser recuperada. Você deve fazer mais.
Para encolher ibdata1 uma vez por todas você deve fazer o seguinte:
1) MySQLDump todos os bancos de dados em um arquivo de texto SQL (chame-o /root/SQLData.sql)
2) Solte todos os bancos de dados (exceto o esquema mysql)
3) mysql de desligamento
4) Adicione as seguintes linhas ao /etc/my.cnf
[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G
Nota: Qualquer que seja o seu conjunto para innodb_buffer_pool_size, verifique se innodb_log_file_size é 25% de innodb_buffer_pool_size.
5) Exclua ibdata1, ib_logfile0 e ib_logfile1
Neste ponto, deve haver apenas o esquema mysql em / var / lib / mysql
6) Reinicie o mysql
Isso recriará o ibdata1 em 10 ou 18MB (dependendo da versão do MySQL), ib_logfile0 e ib_logfile1 em 1G cada
7) Recarregue /root/SQLData.sql no mysql
ibdata1 aumentará, mas conterá apenas metadados da tabela. De fato, crescerá muito lentamente ao longo dos anos. A única maneira de o crescimento do ibdata1 rapidamente é se você tiver um ou mais dos seguintes itens:
- Um monte de DDL (
CREATE TABLE
, DROP TABLE
, ALTER TABLE
)
- Muitas transações
- Muitas alterações a serem confirmadas por transação
Cada tabela do InnoDB existirá fora do ibdata1
Suponha que você tenha uma tabela do InnoDB chamada mydb.mytable. Se você acessar / var / lib / mysql / mydb, verá dois arquivos representando a tabela
- mytable.frm (cabeçalho do mecanismo de armazenamento)
- mytable.ibd (Página inicial dos dados e índices da tabela para mydb.mytable)
O ibdata1 nunca mais conterá dados e índices do InnoDB.
Com a opção innodb_file_per_table em /etc/my.cnf, você pode executar OPTIMIZE TABLE mydb.mytable;
e o arquivo /var/lib/mysql/mydb/mytable.ibd realmente diminui.
Eu fiz isso muitas vezes na minha carreira como um DBA MySQL
De fato, na primeira vez em que fiz isso, reduzi um arquivo ibdata1 de 50 GB em 500 MB.
De uma chance. Se você tiver mais perguntas sobre isso, envie-me um email. Confie em mim. Isso funcionará a curto prazo e a longo prazo !!!
UPDATE 2012-04-19 09:23 EDT
Após executar as etapas acima, como você pode determinar quais tabelas precisam ser desfragmentadas? É possível descobrir, mas você terá um script.
Aqui está um exemplo: Suponha que você tenha a tabela mydb.mytable
. Com innodb_file_per_table ativado, você tem o arquivo /var/lib/mysql/mydb/mytable.ibd
Você terá que recuperar dois números
FILESIZE NO SO: Você pode verificar o tamanho do arquivo no SO dessa maneira
ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'
FILESIZE FROM INFORMATION_SCHEMA: Você pode verificar o tamanho do arquivo de information_schema.tables como este:
SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';
Apenas subtraia o valor de INFORMAÇÃO_SCHEMA do valor do SO e divida a diferença pelo valor de INFORMAÇÃO_SCHEMA.
A partir daí, você decidiria qual porcentagem considera necessário desfragmentar essa tabela. Obviamente, você desfragmenta-o usando um dos seguintes comandos:
OPTIMIZE TABLE mydb.mytable;
ou
ALTER TABLE mydb.mytable ENGINE=InnoDB;