Pregunta ¿Por qué una consulta de inserción ocasionalmente tarda tanto en completarse?


Este es un problema bastante simple. Insertar datos en la tabla normalmente funciona bien, excepto en algunas ocasiones en las que la consulta de inserción tarda unos segundos. (Yo soy no tratando de insertar datos a granel). Por lo tanto, configuré una simulación para el proceso de inserción para averiguar por qué la consulta de inserción ocasionalmente tarda más de 2 segundos en ejecutarse. Joshua sugirió que el archivo de índice puede estar siendo ajustado; Eliminé el id (campo de clave principal), pero la demora aún ocurre.

Tengo una tabla MyISAM: daniel_test_insert (esta mesa comienza completamente vacío):

create table if not exists daniel_test_insert ( 
    id int unsigned auto_increment not null, 
    value_str varchar(255) not null default '', 
    value_int int unsigned default 0 not null, 
    primary key (id) 
)

Inserto datos en él y, a veces, una consulta de inserción tarda más de 2 segundos en ejecutarse. No hay lecturas en esta tabla: solo se escribe, en serie, mediante un único programa de subprocesos.

Ejecuté exactamente la misma consulta 100.000 veces para descubrir por qué la consulta ocasionalmente lleva mucho tiempo. Hasta ahora, parece ser una ocurrencia aleatoria.

Esta consulta, por ejemplo, tardó 4.194 segundos (un tiempo muy largo para una inserción):

Query: INSERT INTO daniel_test_insert SET value_int=12345, value_str='afjdaldjsf aljsdfl ajsdfljadfjalsdj fajd as f' - ran for 4.194 seconds
status               | duration | cpu_user  | cpu_system | context_voluntary | context_involuntary | page_faults_minor
starting             | 0.000042 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
checking permissions | 0.000024 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Opening tables       | 0.000024 | 0.001000  | 0.000000   | 0                 | 0                   | 0                
System lock          | 0.000022 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Table lock           | 0.000020 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
init                 | 0.000029 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
update               | 4.067331 | 12.151152 | 5.298194   | 204894            | 18806               | 477995           
end                  | 0.000094 | 0.000000  | 0.000000   | 8                 | 0                   | 0                
query end            | 0.000033 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
freeing items        | 0.000030 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
closing tables       | 0.125736 | 0.278958  | 0.072989   | 4294              | 604                 | 2301             
logging slow query   | 0.000099 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
logging slow query   | 0.000102 | 0.000000  | 0.000000   | 7                 | 0                   | 0                
cleaning up          | 0.000035 | 0.000000  | 0.000000   | 7                 | 0                   | 0

(Esta es una versión abreviada del comando SHOW PROFILE, arrojé las columnas que eran todas cero).

Ahora la actualización tiene una cantidad increíble de interruptores de contexto y fallas de página menores. Opened_Tables aumenta aproximadamente 1 por 10 segundos en esta base de datos (no se está quedando sin espacio de caché de tabla)

Estadísticas:

  • MySQL 5.0.89

  • Hardware: 32 Gigs de ram / 8 núcleos a 2.66 GHz; atacar 10 discos duros SCSI (SCSI II ???)

  • He consultado los discos duros y el controlador de incursión: no se informaron errores. Las CPU tienen un 50% de inactividad.

  • iostat -x 5 (informa menos del 10% de utilización para discos duros) el promedio de carga del informe superior es de aproximadamente 10 por 1 minuto (lo normal para nuestra máquina db)

  • El espacio de intercambio tiene 156k usado (32 gigas de ram)

No entiendo por qué está causando este retraso en el rendimiento. Esto NO ocurre en nuestros esclavos de carga baja, solo en nuestro maestro de carga alta. Esto también ocurre con la memoria y las tablas innodb. ¿Alguien tiene alguna sugerencia? (Este es un sistema de producción, ¡así que nada exótico!)


32
2017-09-15 23:05


origen


Respuestas:


He notado el mismo fenómeno en mis sistemas. Las consultas que normalmente toman un milisegundo tomarán de repente 1-2 segundos. Todos mis casos son simples, INSERT / UPDATE / REPLACE de una sola tabla --- no en ningún SELECT. Sin carga, bloqueo o acumulación de hilo es evidente.

Sospeché que se debía a borrar páginas sucias, cambios de enrojecimiento en el disco, o algún mutex oculto, pero todavía tengo que reducirlo.

También descartado

  • Carga del servidor: sin correlación con alta carga
  • Motor: sucede con InnoDB / MyISAM / Memory
  • MySQL Query Cache - sucede ya sea que esté activado o desactivado
  • Rotaciones de registros: sin correlación en eventos

La única observación que tengo en este momento se deriva del hecho de que estoy ejecutando el mismo DB en varias máquinas. Tengo una aplicación de lectura pesada, así que estoy usando un entorno con replicación: la mayor parte de la carga está en los esclavos. Me di cuenta de que a pesar de que hay una carga mínima en el maestro, el fenómeno ocurre más allí. Aunque no veo problemas de bloqueo, tal vez Innodb / Mysql tenga problemas con la concurrencia (de subprocesos). Recuerde que las actualizaciones en el esclavo serán de un solo hilo.

MySQL Verion 5.1.48

Actualizar

Creo que tengo una ventaja para el problema en mi caso. En algunos de mis servidores, noté este fenómeno en más que los demás. Al ver lo que era diferente entre los diferentes servidores y ajustar las cosas, fui conducido al Variable de sistema MySQL innodb  innodb_flush_log_at_trx_commit.

El documento me resultó un poco incómodo de leer, pero innodb_flush_log_at_trx_commit puede tomar los valores de 1,2,0:

  • Para 1, el búfer de registro se vacía a el archivo de registro para cada confirmación, y el registro el archivo se vacía en el disco por cada confirmación.
  • Para 2, el búfer de registro se vacía a el archivo de registro para cada confirmación, y el registro el archivo se vacía al disco aproximadamente cada 1-2 segundos.
  • Para 0, el búfer de registro se vacía para el archivo de registro cada segundo y el registro el archivo se vacía al disco cada segundo.

Efectivamente, en el orden (1,2,0), según lo informado y documentado, se supone que debe obtener un mayor rendimiento en el comercio para un mayor riesgo.

Habiendo dicho eso, encontré que los servidores con innodb_flush_log_at_trx_commit=0 funcionaban peor (es decir, tenían 10-100 veces más "actualizaciones largas") que los servidores con innodb_flush_log_at_trx_commit=2. Además, las cosas mejoraron inmediatamente en las malas instancias cuando lo cambié a 2 (tenga en cuenta que puede cambiarlo sobre la marcha).

Entonces, mi pregunta es, ¿a qué se dedicará la tuya? Tenga en cuenta que no culpo a este parámetro, sino que resalto que su contexto está relacionado con este problema.


19
2017-11-09 22:38



Tuve este problema al usar tablas INNODB. (y los índices INNODB son aún más lentos para reescribir que MYISAM)

Supongo que está haciendo muchas otras consultas en otras tablas, por lo que el problema sería que MySQL tiene que manejar las grabaciones de disco en archivos que se hacen más grandes y necesita asignar espacio adicional a esos archivos.

Si usa tablas MYISAM, recomiendo usar

LOAD DATA INFILE 'file-on-disk' INTO TABLE `tablename` 

mando; MYISAM es sensacionalmente rápido con esto (incluso con claves principales) y el archivo puede formatearse como csv y puede especificar los nombres de columna (o puede poner NULL como el valor para el campo de autoincrement).

Ver el documento MYSQL aquí.


1
2017-09-16 08:35



La primera sugerencia que le daría es que desactive la funcionalidad de confirmación automática y que se confirme manualmente.

LOCK TABLES a WRITE;
... DO INSERTS HERE
UNLOCK TABLES;

Esto beneficia el rendimiento porque el búfer de índice se vacía al disco una sola vez, después de que se hayan completado todas las instrucciones INSERT. Normalmente, habrá tantas descargas de búfer de índice como INSERT.

Pero probablemente sea lo mejor que puede hacer, y si eso es posible en su aplicación, debe hacer una inserción masiva con una sola selección.

Esto se hace a través de Vector Binding y es la manera más rápida que puede ir.

Instead
of:
"INSERT INTO tableName values()"
DO
"INSERT INTO tableName values(),(),(),().......(n) " ,

Pero considere esta opción solo si el enlace vectorial de parámetros es posible con su controlador mysql que esté utilizando.

De lo contrario, tendería a la primera posibilidad y BLOQUEAR la tabla por cada 1000 inserciones. No lo bloquee para inserciones de 100k, porque obtendrá un desbordamiento de búfer.


1
2017-09-16 08:46



¿Puedes crear una tabla más con 400 columnas (no nulas) y ejecutar tu prueba nuevamente? Si el número de inserciones lentas aumenta, esto podría indicar que MySQL está perdiendo el tiempo escribiendo sus registros. (No sé cómo funciona, pero puede estar alocando más bloques, o moviendo algo para evitar la fragmentación ... realmente no lo sé)


1
2017-09-22 14:37



Llamamos exactamente el mismo problema e informamos aquí: http://bugs.mysql.com/bug.php?id=62381

Estamos usando 5.1.52 y todavía no tenemos solución. Es posible que necesitemos apagar el control de calidad para evitar este golpe de rendimiento.


1
2017-09-22 10:28



Lea esto en Myisam Performance: http://adminlinux.blogspot.com/2010/05/mysql-allocating-memory-for-caches.html

Buscar:

'El tamaño del bloque de teclas MyISAM El tamaño del bloque de claves es importante' (sin las comillas simples), esto podría ser lo que está sucediendo. Creo que arreglaron algunos de estos tipos de problemas con 5.1


0
2017-09-21 19:49



¿Puedes verificar las estadísticas en el subsistema del disco? ¿Está saturada la E / S? Esto suena como un trabajo interno de DB que va a enjuagar cosas en el disco / registro.


0
2017-09-24 15:10



Para comprobar si su disco se comporta mal y si está en Windows, puede crear un archivo cmd por lotes que cree 10.000 archivos:

@echo OFF
FOR /L %%G IN (1, 1, 10000) DO TIME /T > out%%G.txt

guárdelo en un directorio temporal, como test.cmd

Habilite las extensiones de comando que ejecutan CMD con el parámetro / E: ON

CMD.exe /E:ON

Luego ejecute su lote y vea si el tiempo entre el primer y el último archivo difiere en segundos o segundos.

En Unix / Linux puede escribir un script de shell similar.


0
2017-09-27 15:55



Por casualidad, ¿hay una unidad SSD en el servidor? Algunas unidades SSD sufren de 'studder', que podría causar su síntoma.

En cualquier caso, trataría de averiguar si la demora está ocurriendo en MySQL o en el subsistema del disco.

¿Qué sistema operativo es su servidor y en qué sistema de archivos están los datos de MySQL?


0
2017-10-02 05:29



Actualizamos a MySQL 5.1 y durante este evento, la caché de consultas se convirtió en un problema con muchos "elementos gratuitos". estados de hilos Luego eliminamos el caché de consultas.

O bien, la actualización a MySQL 5.1 o la eliminación de la caché de consultas resolvió este problema.

FYI, para futuros lectores.

-daniel


0
2017-12-09 23:02



si está utilizando la inserción múltiple en uno usando el ciclo for, entonces tome un descanso después de cada ciclo utilizando la función sleep de PHP ("tiempo en segundos").


0
2017-07-22 05:39