Como você remove a fragmentação das tabelas do InnoDB?

13

Eu tenho um banco de dados com número de tabelas.

Quero excluir alguns registros das tabelas, digamos que o número de registros seja superior a 20K ou 50K.

Todas as tabelas são InnoDB. E file_per_tableestá desligado .

Quando excluir os registros de várias tabelas, haverá fragmentação nas tabelas.

Existe alguma maneira de remover a fragmentação.?

Atualização em 17 de abril

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

Então agora minha pergunta é como eu decidirei que minhas tabelas estão fragmentadas ou não.

Abdul Manaf
fonte
1
E um artigo InnoDB: cuide da fragmentação do blog do Percona.
usar o seguinte comando

Respostas:

14

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 TABLEem 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;
RolandoMySQLDBA
fonte
eu não acho que / var / lib / mysql / ibdata1 está muito ocupado se você estiver usando o innodb_file_per_table = 1 opção recomendada
CrackerJack9
1
@ CrackerJack9 ibdata1 é incrivelmente superbusy por causa disso: 1) Informações do buffer de gravação dupla, 2) Buffer de inserção para índices secundários, 3) Dicionário de dados, 4) Segmentos de reversão, 5) Desfazer espaço de tabela. Por favor Goto scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing para uma representação pictórica destas coisas. Mesmo com a remoção de dados e páginas de índice para tabelas do InnoDB, o ibdata1 ainda pode crescer significativamente em um ambiente transacional alto.
RolandoMySQLDBA 4/13
1
@ CrackerJack9 Tenho um posto adicional discutir a atividade adicional em torno ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA
Eu não tinha percebido que ainda era muito usado. Muito apreciado!
precisa saber é o seguinte
@RolandoMySQLDBA Você pode aparecer no Heap quando tiver tempo?
usar o seguinte comando
5

Se você excluir linhas com freqüência (ou atualizar linhas com tipos de dados de comprimento variável), poderá acabar com muito espaço desperdiçado em seu (s) arquivo (s) de dados, semelhante à fragmentação do sistema de arquivos.

Se você não estiver usando a innodb_file_per_tableopção, a única coisa que poderá fazer é exportar e importar o banco de dados, um procedimento que exige muito tempo e disco.

Mas se você estiver usando innodb_file_per_table, poderá identificar e recuperar esse espaço!

Antes da 5.1.21, o contador de espaço livre estava disponível na coluna table_comment de information_schema.tables. Aqui está algum SQL para identificar tabelas com pelo menos 100M (na verdade 97.65M) de espaço livre:

SELECT table_schema, table_name, table_comment FROM
information_schema.tables ONDE O MOTOR GOSTA DE 'InnoDB' E table_comment RLIKE 'InnoDB free: ([0-9] {6,}). *';

A partir do 5.1.21, isso foi movido para a coluna data_free (um local muito mais apropriado):

SELECT table_schema, table_name, data_free / 1024/1024 AS data_free_MB FROM information_schema.tables ONDE O MOTOR GOSTA DE 'InnoDB' E data_free> 100 * 1024 * 1024;

Você pode recuperar o espaço perdido, reconstruindo a tabela. A melhor maneira de fazer isso é usar 'alterar tabela' sem alterar nada:

ALTER TABLE `TableName` ENGINE=InnoDB;

É o que o MySQL faz nos bastidores se você executar 'optimize table' em uma tabela do InnoDB. Isso resultará em um bloqueio de leitura, mas não em um bloqueio de tabela completo. Quanto tempo leva depende completamente da quantidade de dados na tabela (mas não do tamanho do arquivo de dados). Se você possui uma tabela com um grande volume de exclusões ou atualizações, convém executá-la mensalmente ou semanalmente.

Mahesh Patil
fonte
Mais uma coisa eu sou incapaz de entender o que significa data_free> 100 * 1024 * 1024 ..? E quando vi o resultado, sou incapaz de decidir que a tabela está fragmentada ou não ...? Existe alguma maneira de eu posso dizer que a tabela está fragmentada ou não fragmentada.
Abdul Manaf
dê uma olhada na parte minha atualização.
21412 Abdul Manaf