Eu tenho uma tabela InnoDB de 700 GB na qual não estou gravando mais dados (apenas lendo). Gostaria de excluir os dados mais antigos que ele contém e recuperar esse espaço em disco (já que estou ficando sem). A parte de exclusão é bastante fácil, porque eu tenho um índice primário de auto-inc. Para que eu possa iterar em pedaços usando-o e excluir as linhas, mas isso não me trará de volta o espaço. Suponho que OPTIMIZE TABLE
vai, mas isso pode levar uma eternidade em uma mesa de 700 GB, então existe outra opção que estou ignorando?
Editado por RolandoMySQLDBA
Supondo que sua tabela seja mydb.mytable
, execute a seguinte consulta e publique-a aqui para poder determinar o espaço em disco necessário para o encolhimento da tabela:
SELECT
FORMAT(dat/POWER(1024,3),2) datsize,
FORMAT(ndx/POWER(1024,3),2) ndxsize,
FORMAT((dat+ndx)/POWER(1024,3),2) tblsize
FROM (SELECT data_length dat,index_length ndx
FROM information_schema.tables WHERE
table_schema='mydb' AND table_name='mytable') A;
Também precisamos ver a estrutura da tabela, se permitido.
Editar por Noam
Esta é a saída da consulta:
datsize ndxsize tblsize
682,51 47,57 730,08
Esta é a estrutura da tabela ( SHOW CREATE TABLE
)
`CREATE TABLE `mybigtable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL,
`created_at` datetime NOT NULL,
`tid` bigint(20) NOT NULL,
`text` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`ft` tinyint(1) NOT NULL,
`irtsd` bigint(20) NOT NULL,
`irtuid` int(11) NOT NULL,
`rc` int(11) NOT NULL,
`r` tinyint(1) NOT NULL,
`e` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `timezone` varchar(5) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uid_tid` (`uid`,`tid`)) ENGINE=InnoDB AUTO_INCREMENT=2006963844 DEFAULT CHARSET=utf8`
ALTER TABLE ... ENGINE=InnoDB;
(se você tiver espaço para isso). A maioria está satisfeita com seus SSDs muito rápidos e não se preocupa mais.Respostas:
Essa é uma boa pergunta. Você tem várias soluções, mas sua mesa é bastante grande, então nenhuma ficará sem dor :)
Você tem três soluções para "reduzir" as tabelas do InnoDB:
1. OTIMIZAR A TABELA
Você pode usar
OPTIMIZE TABLE
como você mencionou, mas deve se preocupar com ainnodb_file_per_table
variável:Deixe-me explicar:
Com as
OPTIMIZE TABLE
tabelas do InnoDB, bloqueia a tabela, copia os dados em uma nova tabela limpa (é por isso que o resultado é reduzido), descarta a tabela original e renomeia a nova tabela com o nome original. É por isso que você deve ter o dobro da volumetria da sua tabela disponível em seu disco (durante a operação, você precisará de 2x700 GB).Quando você estiver no innodb_file_per_table = ON. Todas as tabelas possuem um arquivo de dados adequado. Portanto, a
OPTIMIZE
instrução criará um novo arquivo de dados (~ 700 GB) quando a operação for concluída, o MySQL descartará o original e renomeará o novo (assim, no final, os 700 GB - provavelmente menos porque serão encolhidos - de dados gerado durante a operação)Quando você estiver no innodb_file_per_table = OFF. Todos os dados vão para um arquivo de dados: ibdata . Este arquivo tem uma particularidade triste, não pode ser reduzido. Portanto, durante o
OPTIMIZE
processo, sua nova tabela será criada (perto de 700 GB), mas mesmo após a operação de remoção e renomeação (e no final daOPTIMIZE
fase), o ibdata não lançará os ~ 700 GB; portanto, você deseja liberar alguns dados, mas possui 700 GB mais legal, não é?2. ALTER TABLE
Você também pode usar uma
ALTER TABLE
declaração,ALTER TABLE
a mesma funcionará da mesma forma queOPTIMIZE TABLE
. Você pode apenas usar:3. ALTER TABLE (ONLINE)
O problema
OPTIMIZE
eALTER TABLE
o travamento da tabela durante a operação. Você pode usar a ferramenta Percona: pt-online-schema-change (do Percona Toolkit: link ). pt-online-schema ... construirá um mecanismo com gatilhos e tabela temporária que permite que a tabela original esteja disponível para leitura e gravação durante a operação. Eu uso essa ferramenta na produção para o grandeALTER
, é muito legal.Observe que você deve ter feito
FOREIGN KEY
referência à sua tabela, FK e dispara o risco de produzir uma bagunça. Para verificar esses pré-requisitos, consulte:Aqui está como eu uso pt-online-schema-change:
Observe que minha observação sobre innodb_file_per_table também é verdadeira para esta solução.
4. mysqldump
A última solução é recriar todos os bancos de dados de um despejo. Terrivelmente longo, mas terrivelmente eficiente. Observe que é a única solução para "reduzir" o arquivo ibdata.
Máx.
fonte
Se você tem pouco tamanho de disco, sugiro que você faça exatamente o que Max sugeriu com pt-online-schema-change (ONLINE). Eu estive na mesma situação com uma tabela muito menor (200 GB) e escolhi fazer alguma compactação ao mesmo tempo. Algo nesse sentido deve funcionar:
Isso funcionará apenas se você estiver no formato de arquivo barracuda e no formato COMPACT da tabela. Além disso, você deve ter innodb_file_per_table ativado. Isso pode surpreender o tamanho da sua tabela, especialmente se houver muito texto e se você usar KEY_BLOCK_SIZE menor, como 8K ou até 4K (o padrão é 16K). Você também pode verificar quanto espaço você pode ganhar com vários benchmarks em relação a esse problema em outros blogs, mas a documentação do MySQL anuncia 25% a 50% (quase 90% para mim).
Observe que isso também pode afetar o desempenho ao executar SELECTs (da documentação do MySQL):
O MySQL também precisa descompactar os dados quando não estiver no buffer pool. Então esteja avisado.
Isso realmente funcionou bem no meu caso. Eu tive um texto longo. 200GB tornaram-se 26GB. Performances não foram alteradas.
Para informações mais detalhadas, verifique estes links:
https://dev.mysql.com/doc/refman/5.5/en/innodb-compression-usage.html
https://dev.mysql.com/doc/refman/5.5/en/innodb-compression-internals.html
fonte