2010-09-09 7 views
13

Estoy trabajando con una tabla enorme que tiene más de 250 filas. El esquema es simple.El rendimiento de inserción de MySQL se degrada en una tabla grande

CREATE TABLE MyTable (
     id BIGINT PRIMARY KEY AUTO_INCREMENT, 
     oid INT NOT NULL, 
     long1 BIGINT NOT NULL, 
     str1 VARCHAR(30) DEFAULT NULL, 
     str2 VARCHAR(30) DEFAULT NULL, 
     str2 VARCHAR(200) DEFAULT NULL, 
     str4 VARCHAR(50) DEFAULT NULL, 
     int1 INT(6) DEFAULT NULL, 
     str5 VARCHAR(300) DEFAULT NULL, 
     date1 DATE DEFAULT NULL, 
     date2 DATE DEFAULT NULL, 
     lastUpdated TIMESTAMP NOT NULL, 
     hashcode INT NOT NULL, 
     active TINYINT(1) DEFAULT 1, 
     KEY oid(oid), 
     KEY lastUpdated(lastUpdated), 
     UNIQUE KEY (hashcode, active), 
     KEY (active) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 MAX_ROWS=1000000000; 

El rendimiento de la inserción ha disminuido significativamente. Hasta 150 millones de filas en la tabla, solía tardar de 5 a 6 segundos para insertar 10.000 filas. Ahora ha aumentado entre 2 y 4 veces. El archivo ibdata de Innodb ha crecido a 107 GB. Los parámetros de configuración de Innodb son los siguientes.

innodb_buffer_pool_size = 36G # Machine has 48G memory 
innodb_additional_mem_pool_size = 20M 
innodb_data_file_path = ibdata1:10M:autoextend 
innodb_log_file_size = 50M 
innodb_log_buffer_size = 20M 
innodb_log_files_in_group=2 
innodb_flush_log_at_trx_commit = 1 
innodb_lock_wait_timeout = 50 
innodb_thread_concurrency = 8 
innodb_flush_method = O_DIRECT 
expire_logs_days = 4 

IO ha pasado el tiempo de espera como se ve con top. He intentado cambiar el método de descarga a O_DSYNC, pero no ayudó. El disco está tallado en la configuración RAID 10 de hardware. En una configuración anterior con un solo disco, IO no era un problema.

¿Particiona solo la opción de tabla? ¿Puede ayudar a dividir archivos individuales de 100G en archivos "más pequeños"? ¿Hay alguna variable que deba ser ajustada para RAID?

Actualización: Este es un sistema de prueba. Tengo la libertad de hacer los cambios necesarios.

Respuesta

13

No dijo si se trataba de un sistema de prueba o producción; Supongo que es producción.

Es probable que tenga la tabla en un tamaño donde sus índices (o el lote completo) ya no quepan en la memoria.

Esto significa que InnoDB debe leer las páginas durante las inserciones (según la distribución de los valores de índice de las nuevas filas). Leer páginas (lecturas aleatorias) es realmente lento y debe evitarse si es posible.

El particionamiento parece ser la solución más obvia, pero el particionamiento de MySQL puede no ajustarse a su caso de uso.

Sin duda, debería considerar todas las opciones posibles: lleve la tabla a un servidor de prueba en su laboratorio para ver cómo se comporta.

Tu clave principal me parece que posiblemente no sea necesaria (tienes otro índice único), por lo que eliminar esa es una opción.

Considere también el complemento innodb y la compresión, esto hará que su innodb_buffer_pool vaya más allá.

Realmente necesita analizar sus casos de uso para decidir si realmente necesita conservar todos estos datos y si el particionamiento es una solución sensata.

Hacer cambios en esta aplicación es probable que introduzca nuevos problemas de rendimiento para los usuarios, por lo que debe tener mucho cuidado aquí. Si encuentra una forma de mejorar el rendimiento de inserción, es posible que reduzca el rendimiento de búsqueda o el rendimiento de otras operaciones. Deberá realizar una prueba de rendimiento completa en un hardware de grado de producción antes de liberar dicho cambio.

+1

Gracias, Mark.This es un sistema de prueba. –

+0

Su consejo sobre el tamaño del índice es útil. Estoy trabajando en la indexación. –

2

Como MarkR comentó anteriormente, el rendimiento de inserción empeora cuando los índices ya no caben en su grupo de búferes. InnoDB tiene un mecanismo de reducción de E/S aleatorio (llamado el búfer de inserción) que evita parte de este problema, pero no funcionará en su índice UNIQUE. El índice de (código hash, activo) debe verificarse en cada inserción, asegúrese de que no se inserten entradas duplicadas. Si el código hash no 'sigue' la clave principal, esta comprobación podría ser IO aleatorio.

¿Tiene la posibilidad de cambiar el esquema?

Su mejor apuesta es:

(a) Hacer código hash alguien secuencial, o ordenar por código hash antes de insertar a granel (esto por sí mismo le ayudará, ya lecturas aleatorias se reducirá).

(b) Convierta (hashcode, active) la clave principal e inserte los datos en orden ordenado. Supongo que su aplicación probablemente se lee mediante hashcode y que la búsqueda de la clave principal es más rápida.

4

Según mi experiencia con Innodb, parece alcanzar un límite para los sistemas de escritura intensiva incluso si tiene un subsistema de disco realmente optimizado. Me sorprende que haya logrado obtener hasta 100 GB.

Esto es lo que Twitter tocó hace un tiempo y se dio cuenta de que necesitaba fragmentarse - ver http://github.com/twitter/gizzard.

Todo esto depende de sus casos de uso, sino que también podría pasar de MySQL a Cassandra ya que realiza muy bien para aplicaciones intensivas de escritura. (Http://cassandra.apache.org)

1

Usted no ha mencionado cómo es tu carga de trabajo, pero si no hay demasiadas lecturas o si tienes suficiente memoria principal, otra opción es usar un back-end optimizado para escritura para MySQL, en lugar de innodb. Tokutek reclama insertos 18 veces más rápidos y una curva de rendimiento mucho más plana a medida que crece el conjunto de datos.

tokutek.com

http://tokutek.com/downloads/tokudb-performance-brief.pdf

0

voy segundos @ los comentarios de MarkR sobre la reducción de los índices. Otra cosa que debes considerar es aumentar tu innodb_log_file_size. Aumenta el tiempo de recuperación de fallos, pero debería ayudar. Tenga en cuenta que necesita eliminar los archivos antiguos antes de reiniciar el servidor.

general InnoDB sugerencias de ajuste: http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/

También debe ser consciente de LOAD DATA INFILE para hacer insertos. Es mucho más rápido.

0

Aumento de innodb_log_file_size = 50M a innodb_log_file_size = 500M

Y el innodb_flush_log_at_trx_commit debe ser 0 si se tiene la pérdida de datos 1 seg.

Cuestiones relacionadas