Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Comprimento médio da linha maior do que o possível

  • Porque avg_row_length é data_length / rows .

data_length é basicamente o tamanho total da tabela no disco . Uma tabela InnoDB é mais do que apenas uma lista de linhas. Portanto, há essa sobrecarga extra.
  • Porque uma linha do InnoDB é mais do que os dados.

Semelhante ao acima, cada linha vem com alguma sobrecarga. Então isso vai aumentar o tamanho de uma linha. Uma tabela InnoDB também não é apenas uma lista de dados amontoados. Ele precisa de um pouco de espaço vazio extra para funcionar com eficiência.
  • Porque as coisas são armazenadas em discos em blocos e esses blocos nem sempre estão cheios.

Os discos armazenam coisas geralmente em 4K, 8K ou 16K blocos . Às vezes, as coisas não se encaixam perfeitamente nesses blocos, então você pode obter algumas vazias espaço .

Como veremos abaixo, o MySQL vai alocar a tabela em blocos. E vai alocar muito mais do que precisa para evitar ter que aumentar a tabela (o que pode ser lento e levar a fragmentação de disco o que torna as coisas ainda mais lentas).

Para ilustrar isso, vamos começar com uma tabela vazia.
mysql> create table foo ( id smallint(5) unsigned NOT NULL );
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |          0 |              0 |
+-------------+------------+----------------+

Ele usa 16K, ou quatro blocos de 4K, para não armazenar nada. A tabela vazia não precisa desse espaço, mas o MySQL o alocou assumindo que você colocaria um monte de dados nela. Isso evita ter que fazer uma dispendiosa realocação em cada inserto.

Agora vamos adicionar uma linha.
mysql> insert into foo (id) VALUES (1);
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |          1 |          16384 |
+-------------+------------+----------------+

A mesa não ficou maior, há todo aquele espaço não utilizado dentro desses 4 blocos que ela tem. Há uma linha que significa um avg_row_length de 16K. Claramente absurdo. Vamos adicionar outra linha.
mysql> insert into foo (id) VALUES (1);
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |          2 |           8192 |
+-------------+------------+----------------+

Mesma coisa. 16 K são alocados para a tabela, 2 linhas usando esse espaço. Um resultado absurdo de 8K por linha.

À medida que insiro mais e mais linhas, o tamanho da tabela permanece o mesmo, está usando cada vez mais espaço alocado e o avg_row_length se aproxima da realidade.
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';                                                                     
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |       2047 |              8 |
+-------------+------------+----------------+

Aqui também começamos a ver table_rows tornar impreciso. Eu definitivamente inseri 2048 linhas.

Agora, quando eu insiro um pouco mais...
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       98304 |       2560 |             38 |
+-------------+------------+----------------+

(Eu inseri 512 linhas e table_rows voltou à realidade por algum motivo)

O MySQL decidiu que a tabela precisa de mais espaço, então foi redimensionada e pegou muito mais espaço em disco. avg_row_length apenas pulou novamente.

Ele pegou muito mais espaço do que o necessário para essas 512 linhas, agora são 96K ou 24 blocos de 4K, supondo que será necessário mais tarde. Isso minimiza quantas realocações potencialmente lentas ele precisa fazer e minimiza a fragmentação do disco.

Isso não significa que todo o espaço foi preenchido . Significa apenas que o MySQL pensou que estava cheio o suficiente para precisar de mais espaço para ser executado com eficiência. Se você quiser ter uma ideia do motivo, veja como uma tabela de hash opera. Não sei se o InnoDB usa uma tabela de hash, mas o princípio se aplica:algumas estruturas de dados funcionam melhor quando há algum espaço vazio.

O disco usado por uma tabela está diretamente relacionado ao número de linhas e tipos de colunas na tabela, mas a fórmula exata é difícil de descobrir e mudará de versão para versão do MySQL. Sua melhor aposta é fazer alguns testes empíricos e se resignar que você nunca obterá um número exato.