sql >> Base de Datos >  >> RDS >> Mysql

Longitud de fila promedio más alta de lo posible

  • Porque avg_row_length es data_length / rows .

data_length es básicamente el tamaño total de la tabla en el disco . Una tabla InnoDB es más que una lista de filas. Así que hay gastos generales adicionales.

  • Porque una fila de InnoDB es más que los datos.

Similar al anterior, cada fila viene con algunos gastos generales. Así que eso se sumará al tamaño de una fila. Una tabla InnoDB tampoco es solo una lista de datos amontonados. Necesita un poco de espacio vacío adicional para funcionar de manera eficiente.

  • Porque las cosas se almacenan en discos en bloques y esos bloques no siempre están llenos.

Los discos almacenan cosas generalmente en bloques de 4K, 8K o 16K. . A veces, las cosas no encajan perfectamente en esos bloques, por lo que puede obtener algunos vacíos espacio .

Como veremos a continuación, MySQL va a asignar la tabla en bloques. Y va a asignar mucho más de lo que necesita para evitar tener que hacer crecer la tabla (que puede ser lento y conducir a fragmentación de disco lo que hace que las cosas sean aún más lentas).

Para ilustrar esto, comencemos con una tabla vacía.

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 |
+-------------+------------+----------------+

Utiliza 16K, o cuatro bloques de 4K, para almacenar nada. La tabla vacía no necesita este espacio, pero MySQL lo asignó asumiendo que vas a poner un montón de datos en ella. Esto evita tener que realizar una costosa reasignación en cada inserto.

Ahora agreguemos una fila.

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 |
+-------------+------------+----------------+

La mesa no se hizo más grande, está todo ese espacio sin usar dentro de esos 4 bloques que tiene. Hay una fila que significa un avg_row_length de 16K. Claramente absurdo. Agreguemos otra fila.

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 |
+-------------+------------+----------------+

La misma cosa. Se asignan 16K para la tabla, 2 filas que usan ese espacio. Un resultado absurdo de 8K por fila.

A medida que inserto más y más filas, el tamaño de la tabla sigue siendo el mismo, utiliza cada vez más espacio asignado y avg_row_length se acerca a la realidad.

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 |
+-------------+------------+----------------+

Aquí también comenzamos a ver table_rows volverse impreciso. Definitivamente inserté 2048 filas.

Ahora, cuando inserto un poco más...

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 |
+-------------+------------+----------------+

(Inserté 512 filas y table_rows ha vuelto a la realidad por alguna razón)

MySQL decidió que la tabla necesita más espacio, por lo que se redimensionó y ocupó mucho más espacio en disco. avg_row_length acaba de saltar de nuevo.

Tomó mucho más espacio del que necesita para esas 512 filas, ahora son 96K o 24 bloques 4K, suponiendo que lo necesitará más adelante. Esto minimiza la cantidad de reasignaciones potencialmente lentas que necesita hacer y minimiza la fragmentación del disco.

Esto no significa que se llenó todo ese espacio . Simplemente significa que MySQL pensó que estaba lo suficientemente lleno como para necesitar más espacio para ejecutarse de manera eficiente. Si quieres tener una idea de por qué es así, investiga cómo una tabla hash opera. No sé si InnoDB usa una tabla hash, pero se aplica el principio:algunas estructuras de datos funcionan mejor cuando hay espacio vacío.

El disco utilizado por una tabla está directamente relacionado con la cantidad de filas y tipos de columnas en la tabla, pero la fórmula exacta es difícil de descifrar y cambiará de una versión a otra de MySQL. Su mejor apuesta es hacer algunas pruebas empíricas y resignarse a que nunca obtendrá un número exacto.