Manutenção de índices MySQL

12

Fiz muita pesquisa sobre como manter índices no MySQL para impedir a fragmentação e otimizar de alguma forma a execução de algumas consultas.

Eu estou familiarizado com essa fórmula que calcula a proporção entre o espaço máximo disponível para uma tabela e o espaço usado por dados e índices.

No entanto, minhas principais perguntas ainda não foram respondidas. Talvez isso se deva ao fato de eu estar familiarizado com a manutenção de índices no SQL Server e ter a tendência de pensar que no MySQL deve ser algo semelhante.

No SQL Server, você pode ter vários índices e cada um deles pode ter diferentes níveis de fragmentação. Em seguida, você pode escolher um e executar uma operação 'REORGANIZE' ou 'REBUILD' nesse índice específico, sem afetar o restante.

Que eu saiba, não existe uma 'fragmentação de tabela' e o SQL Server não fornece nenhuma ferramenta para corrigir a 'fragmentação de tabela'. O que ele fornece são ferramentas para verificar a fragmentação do índice (entendida como a proporção entre o número de páginas usadas por um índice e a plenitude dessa página e contiguidade), bem como a fragmentação interna e externa.

Tudo isso é bastante simples de entender, pelo menos para mim.

Agora, quando chega a hora de manter índices no MySQL, existe apenas o conceito de 'fragmentação de tabela', como mencionado acima.

Uma tabela no MySQL pode ter vários índices, mas quando eu checo a 'taxa de fragmentação' com essa famosa fórmula, não vejo a fragmentação de cada índice, mas a tabela como um todo.

Quando quero otimizar os índices no MySQL, não escolho um índice específico para operar (como no SQL Server). Em vez disso, eu faço uma operação 'OPTIMIZE' em toda a tabela, o que presumivelmente afeta todos os índices.

Quando a tabela é otimizada no MySQL, a proporção entre o espaço usado pelos dados + índices e o espaço geral é reduzida, o que sugere algum tipo de reorganização física no disco rígido, o que se traduz em uma redução do espaço físico. No entanto, a fragmentação do índice não se refere apenas ao espaço físico, mas à estrutura da árvore que foi alterada ao longo do tempo devido a inserções e atualizações.

Finalmente, consegui uma tabela no InnoDB / MySQL. Essa tabela possui 3 milhões de registros, 105 colunas e 55 índices. São 1,5 GB, excluindo índices, que são 2,1 GB.

Essa tabela está sendo atingida milhares de vezes por dia para atualização e inserção (na verdade, não excluímos registros).

Essa tabela foi criada há anos e eu tenho certeza de que ninguém mantém nenhum índice.

Eu esperava encontrar uma enorme fragmentação lá, mas quando eu executo o cálculo de fragmentação conforme prescrito

free_space / (data_length + index_length)

Acontece que eu tenho apenas uma fragmentação de 0,2%. IMHO que é bastante irreal.

Portanto, as grandes questões são:

  1. Como verifico a fragmentação de um índice específico no MySQL, não a tabela como um todo
  2. O OPTIMIZE TABLE realmente corrige a fragmentação interna / externa de um índice como no SQL Server?
  3. Quando otimizo uma tabela no MySQL, ele realmente recria todos os índices da tabela?
  4. É realista pensar que reduzir o espaço físico de um índice (sem reconstruir a própria árvore) realmente se traduz em um melhor desempenho?
Nicolas
fonte
OPTIMIZE TABLE certamente limpa o índice agrupado na InnoDB
11
é uma ótima pergunta, mas não de programação. Será movido para o lugar em que ele pertence:>

Respostas:

6

A fragmentação do índice é muito superestimada. Não se preocupe com isso.

Dois blocos adjacentes, um tanto vazios, são mesclados pelo InnoDB como o processamento natural.

Ações aleatórias em um BTree fazem com que ele gravite naturalmente em direção a uma média de 69% da capacidade total. Claro, isso não é 100%, mas a sobrecarga de "consertar" não vale a pena.

SHOW TABLE STATUS fornece algumas métricas, mas são falhas - "Data_free" inclui certo espaço "livre", mas não outro espaço "livre".

Há espaço não utilizado em cada bloco; blocos gratuitos de 16 KB; "extensões" livres (pedaços de nMB); Linhas MVCC aguardando para serem colhidas; nós não-folha têm sua própria fragmentação; etc.

A Percona e a Oracle têm maneiras diferentes de ver o tamanho (número de blocos) de um índice. Acho que nenhum deles é útil por causa da definição limitada de "livre". Parece que os blocos (16 KB cada) são alocados em blocos (vários MB), levando-os a acreditar que há todo tipo de fragmentação. Na realidade, geralmente é apenas a maioria de um desses blocos com vários MB. E OPTIMIZE TABLEnão recupera necessariamente nada do espaço.

Se o SQL Server estiver usando o BTrees, é mentira dizer que "não há fragmentação". Pense no que acontece em uma "divisão de bloco". Ou pense na sobrecarga de desfragmentar continuamente. De qualquer maneira você perde.

Observe também que uma tabela e um índice são estruturas essencialmente idênticas:

  • Árvore B +, com base em algum índice
  • Os "dados" são baseados na CHAVE PRIMÁRIA; cada índice secundário é uma árvore B + com base em seu índice.
  • O nó folha dos "dados" contém todas as colunas da tabela.
  • O nó folha de um índice secundário contém as colunas desse índice secundário, mais as colunas da PRIMARY KEY.

Se você tiver innodb_file_per_table = ON, poderá ver claramente o encolhimento (se houver) após OPTIMIZE TABLE observando o .ibdtamanho do arquivo. Pois OFF, as informações estão ocultas ibdata1, mas SHOW TABLE STATUSpodem ser razoavelmente precisas, pois todo o espaço "livre" pertence a todas as tabelas. Bem, exceto pelos pedaços pré-alocados.

Você pode perceber que uma tabela de arquivo por tabela recém-otimizada possui exatamente 4M, 5M, 6M ou 7M de Data_free. Novamente, essa é a pré-alocação e a falha em fornecer os detalhes minuciosos.

Eu trabalho com o InnoDB há mais de uma década; Eu trabalhei com milhares de tabelas diferentes, grandes e pequenas. Eu digo que apenas uma mesa em cada mil precisa realmente OPTIMIZE TABLE. Usá-lo em outras mesas é um desperdício.

105 colunas é muito, mas talvez não muitas.

Você tem 55 índices em uma tabela? Isso é mau. São 55 atualizações por INSERT. Vamos discutir isso mais. Tenha em mente que INDEX(a)é inútil se você também tiver INDEX(a,b). E INDEX(flag)é inútil por causa da baixa cardinalidade. (Mas INDEX(flag, foo)pode ser útil.)

T1: Não há uma boa maneira de verificar todas as formas de fragmentação nos dados ou nos índices secundários.

Q2, Q3: OPTIMIZE TABLEreconstrói a tabela por CREATEinguma nova tabela e INSERTingtodas as linhas, depois RENAMEinge DROPping. A reinserção dos dados na ordem PK garante que os dados sejam bem desfragmentados. Os índices são outra questão.

Q4: você pode DROP e reCREATEcada índice para limpá-lo. Mas este é um processo extremamente lento. A versão 5.6 tem algumas melhorias, mas não sei se elas ajudam na desfragmentação.

Também é possível ALTER TABLE ... DISABLE KEYS, então ENABLEeles. Isso pode resultar em uma reconstrução mais eficiente de todos os índices secundários de uma só vez.

Rick James
fonte
Rick, eu quis dizer '105' campos, não arquivos
Nicolas
1

Como verifico a fragmentação de um índice específico no MySQL, não a tabela como um todo

Passar.

O OPTIMIZE TABLE realmente corrige a fragmentação interna / externa de um índice como no SQL Server?

Ele reconstrói completamente a tabela e seus índices.

Quando otimizo uma tabela no MySQL, ele realmente recria todos os índices da tabela?

Essa é a mesma pergunta com a mesma resposta.

É realista pensar que reduzir o espaço físico de um índice (sem reconstruir a própria árvore) realmente se traduz em um melhor desempenho?

Não é realista pensar que você poderia reduzir o espaço sem reconstruir a árvore. Eles vão juntos.

user207421
fonte
Resposta 1: Embora não seja muito preciso, mas SHOW TABLE STATUS LIKE 'mytable'daria uma dica na data freecoluna. dev.mysql.com/doc/refman/5.6/en/show-table-status.html
Jehad Keriaki
Eu sei, mas que ainda está faltando o espaço de um determinado índice
Nicolas