2010-05-26 20 views
7

Estoy tratando de averiguar los requisitos de almacenamiento para diferentes motores de almacenamiento. Tengo esta tabla:¿Por qué el tamaño de la tabla InnoDB es mucho más grande de lo esperado?

CREATE TABLE `mytest` (
    `num1` int(10) unsigned NOT NULL, 
    KEY `key1` (`num1`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Al insertar algunos valores y luego corro show table status; me sale el siguiente:

 
+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ 
| Name   | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time   | Update_time   | Check_time | Collation   | Checksum | Create_options | Comment | 
+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ 
| mytest   | InnoDB |  10 | Compact | 1932473 |    35 | 67715072 |    0 |  48840704 | 4194304 |   NULL | 2010-05-26 11:30:40 | NULL    | NULL  | latin1_swedish_ci |  NULL |    |   | 

Aviso AVG_ROW_LENGTH es 35. Estoy sorprendido de que InnoDB no sería hacer un mejor uso del espacio cuando solo estoy almacenando un entero no nulable.

He ejecutado esta misma prueba en myISAM y de forma predeterminada myISAM utiliza 7 bytes por fila en esta tabla. Cuando ejecuto

ALTER TABLE mytest MAX_ROWS=50000000, AVG_ROW_LENGTH = 4; 

hace que myISAM finalmente utilice correctamente filas de 5 bytes.

Cuando ejecuto la misma sentencia ALTER TABLE para InnoDB, avg_row_length no cambia.

¿Por qué un avg_row_length tan grande sería necesario cuando solo se almacena un int sin firmar de 4 bytes?

+0

Acabo de leer que InnoDB usa el tablespace tanto para los datos como para el índice. esto tiene sentido y parece que esta sería la razón por la que estoy viendo una avg_row_length tan grande ... tal vez. También descubrí que cada nodo hoja almacena la identificación de la transacción y el puntero de restitución. Bueno, no estoy haciendo uso de las transacciones per se y por lo tanto no tengo uso para estos datos. ¿Hay alguna forma de no almacenar estos valores? ¿De alguna manera puedo usar InnoDB pero hacer un uso un poco mejor del almacenamiento? gracias! –

+0

@alessandro: sí, el soporte de transacción también agrega algo de sobrecarga. El hecho de que no esté haciendo uso de las transacciones no significa que no se utilicen: por ejemplo, un hilo que muere durante una operación larga de 'ACTUALIZACIÓN' se revertirá correctamente en 'InnoDB' pero no en 'MyISAM'. El soporte de transacción es el objetivo de usar 'InnoDB', si no lo necesita, solo use' MyISAM'. – Quassnoi

+0

@Quassnoi: Tengo la impresión de que MyISAM no está tan "maduro" o preparado para producción como InnoDB ... tal vez sea un miedo infundado. ¿Hay alguna dificultad que MyISAM trae a la mesa cuando se trata de hacer copias de seguridad de las bases de datos además del hecho de que MyISAM requiere un bloqueo de tabla completo para garantizar la coherencia. No requiero transacciones y almacenaré muchos datos. ¿Hay algún problema conocido con MyISAM que pueda causar que no lo use? –

Respuesta

10

InnoDB tablas están agrupadas, eso significa que todos los datos están contenidos en un B-Tree con el PRIMARY KEY como clave y todas las demás columnas como una carga útil.

Dado que no se define explícitamente una PRIMARY KEY, InnoDB utiliza una columna de 6 bytes oculto para ordenar los registros en.

Esto y la parte superior de la organización B-Tree (con bloques extra a nivel de hoja) requiere más espacio que sizeof(int) * num_rows.

0

Además de la muy buena respuesta de Quassnoi, probablemente debería probarlo usando un conjunto de datos significativo.

Lo que yo haría es cargar filas de 1M de datos de producción simulados, luego medir el tamaño de la tabla y usar eso como guía.

Eso es lo que I've done in the past anyway

+0

Sí, gracias MarkR, lo había hecho con un conjunto de datos de 50 millones de filas. InnoDB utilizó más de 3 veces más espacio en 3GIGs –

+0

Basado en mi estudio (ver enlace arriba), esto es típico; puede usar menos espacio usando el complemento y activando la compresión. Ver la publicación de mi blog para algunos datos. – MarkR

2

Aquí hay más información que puede resultar útil.

InnoDB asigna datos en términos de páginas de 16KB, por lo que 'SHOW TABLE STATUS' dará números inflados por tamaño de fila si sólo tiene un par de filas y la mesa es < 16K total. (Por ejemplo, con 4 filas, el tamaño de fila promedio regresa como 4096.)

Los 6 bytes adicionales por fila para la clave primaria "invisible" son un punto crucial cuando el espacio es una gran consideración. Si la tabla es sólo una columna, que es la columna ideal para hacer que la clave primaria, asumiendo los valores que son únicos:

CREATE TABLE `mytest2` 
     (`num1` int(10) unsigned NOT NULL primary key) 
ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Mediante el uso de una PRIMARY KEY como esto:

  1. ningún índice o La cláusula KEY es necesaria, porque no tienes un índice secundario. El formato organizado por índice de las tablas InnoDB le ofrece una búsqueda rápida basada en el valor de la clave primaria de forma gratuita.
  2. No termina con otra copia de los datos de la columna NUM1, que es lo que sucede cuando esa columna se indexa explícitamente.
  3. No termina con otra copia de los valores de clave primaria invisible de 6 bytes. Los valores de las claves primarias están duplicados en cada índice secundario. (Esa también es la razón por la que probablemente no desee 10 índices en una tabla con 10 columnas, y probablemente no desee una clave principal que combine varias columnas diferentes o una columna de cadena larga.)

Entonces, en general, quedarse con solo una clave primaria significa menos datos asociados con los índices de tabla +. Para tener una idea del tamaño total de datos, me gusta correr con

set innodb_file_per_table = 1; 

y examinar el tamaño de los datos/ base de datos de archivos /*table*.ibd. Cada archivo .ibd contiene los datos de una tabla InnoDB y todos sus índices asociados.

para construir rápidamente una gran mesa para las pruebas, por lo general ejecuta una instrucción de este modo:

insert into mytest 
select * from mytest; 

que se duplica la cantidad de datos cada vez. En el caso de la mesa de una sola columna usando una clave principal, ya que los valores tuvieron que ser único, I utilizado una variación de mantener los valores de chocar unos con otros:

insert into mytest2 
select num1 + (select count(*) from mytest2) from mytest2; 

De esta manera, pude obtener el tamaño de fila promedio hasta 25. La sobrecarga de espacio se basa en la suposición subyacente de que desea tener una búsqueda rápida de filas individuales utilizando un mecanismo de estilo de puntero, y la mayoría de las tablas tendrá una columna cuyos valores sirven como punteros (es decir, el clave) además de las columnas con datos reales que se suman, se promedian y se muestran.

+0

Excelente información aquí, gracias por compartir. – dkamins

Cuestiones relacionadas