¿Qué es más rápido: múltiples INSERT individuales o un INSERT de múltiples filas?

Estoy tratando de optimizar una parte de mi código que inserta datos en MySQL. ¿Debo encadenar INSERT para hacer un INSERT GRANDE de múltiples filas o más INSERT múltiples por separado más rápido?

http://dev.mysql.com/doc/refman/5.0/en/insert-speed.html

El tiempo requerido para insertar una fila está determinado por los siguientes factores, donde los números indican proporciones aproximadas:

  • Conectando: (3)
  • Enviando consulta al servidor: (2)
  • Consulta de análisis: (2)
  • Insertar fila: (1 × tamaño de la fila)
  • Insertar índices: (1 × número de índices)
  • Cierre: (1)

A partir de esto, debería ser obvio, que enviar una statement grande le ahorrará una sobrecarga de 7 por statement de inserción, lo que al leer más el texto también dice:

Si está insertando muchas filas del mismo cliente al mismo tiempo, use las instrucciones INSERT con múltiples listas VALUES para insertar varias filas a la vez. Esto es considerablemente más rápido (muchas veces más rápido en algunos casos) que el uso de instrucciones INSERT separadas de una sola fila.

Sé que estoy respondiendo esta pregunta casi dos años y medio después de que me lo pidieron, pero solo quería proporcionar algunos datos concretos de un proyecto en el que estoy trabajando ahora que muestra que, de hecho, hacer MÚLTIPLES bloques por inserción es MUCHO más rápido que las sentencias INSERT de bloque de VALOR único secuencial.

El código que escribí para este punto de referencia en C # usa ODBC para leer datos en la memoria de una fuente de datos MSSQL (~ 19,000 filas, todas se leen antes de que comience cualquier escritura), y el conector MySql .NET (Mysql.Data. *) INSERTAR los datos de la memoria en una tabla en un servidor MySQL mediante declaraciones preparadas. Fue escrito de tal manera que me permitiera ajustar dinámicamente el número de bloques de VALOR por INSERT preparado (es decir, insertar n filas a la vez, donde podría ajustar el valor de n antes de una ejecución). También realicé la prueba varias veces para cada n.

Hacer solo bloques de VALOR (por ejemplo, 1 fila a la vez) tomó 5.7 – 5.9 segundos para ejecutarse. Los otros valores son los siguientes:

2 filas a la vez: 3.5 – 3.5 segundos
5 filas a la vez: 2.2 – 2.2 segundos
10 filas a la vez: 1.7 – 1.7 segundos
50 filas a la vez: 1.17 – 1.18 segundos
100 filas a la vez: 1.1 – 1.4 segundos
500 filas a la vez: 1.1 – 1.2 segundos
1000 filas a la vez: 1.17 – 1.17 segundos

Así que sí, incluso agrupar 2 o 3 escrituras juntas proporciona una mejora dramática en la velocidad (corte de tiempo de ejecución por un factor de n), hasta llegar a algo entre n = 5 yn = 10, momento en el que la mejora disminuye marcadamente, y en algún lugar en el rango de n = 10 a n = 50 la mejora se vuelve insignificante.

Espero que ayude a las personas a decidir (a) si usar la idea de multiplicación múltiple y (b) cuántos bloques de VALOR crear por statement (suponiendo que desee trabajar con datos que puedan ser lo suficientemente grandes como para pasar la consulta al tamaño máximo de consulta) para MySQL, que creo que es de 16 MB por defecto en muchos lugares, posiblemente más grande o más pequeño según el valor de max_allowed_packet establecido en el servidor).

Un factor importante será si está utilizando un motor transaccional y si tiene activado el autocommitido.

La confirmación automática está activada de manera predeterminada y es probable que desee dejarla activada; por lo tanto, cada inserción que haces hace su propia transacción. Esto significa que si hace una inserción por fila, va a comprometer una transacción para cada fila.

Suponiendo un único hilo, eso significa que el servidor necesita sincronizar algunos datos con el disco por CADA FILA. Necesita esperar a que los datos lleguen a una ubicación de almacenamiento persistente (es de esperar que el RAM de respaldo de la batería en su controlador RAID). Esto es intrínsecamente lento y probablemente se convierta en el factor limitante en estos casos.

Por supuesto, supongo que está utilizando un motor transaccional (generalmente innodb) Y que no ha ajustado las configuraciones para reducir la durabilidad.

También estoy asumiendo que estás usando un solo hilo para hacer estas inserciones. El uso de varios subprocesos complica un poco las cosas porque algunas versiones de MySQL tienen un grupo de trabajo comprometido en innodb, lo que significa que varios subprocesos pueden compartir una sola escritura en el registro de transacciones, lo que es bueno porque significa menos sincronizaciones con el almacenamiento persistente. .

Por otro lado, el resultado es que REALMENTE QUIERES UTILIZAR inserciones de varias hileras.

Existe un límite sobre el cual se vuelve contraproducente, pero en la mayoría de los casos es de al menos 10,000 filas. Entonces, si los lotes hasta 1.000 filas, probablemente estés a salvo.

Si usas MyISAM, hay muchas cosas más, pero no te aburriré con eso. Paz.

Envíe tantas inserciones a través del cable a la vez como sea posible. La velocidad de inserción real debe ser la misma, pero verá mejoras en el rendimiento a partir de la reducción de la sobrecarga de la red.

En general, cuanto menor sea el número de llamadas a la base de datos, mejor (es decir, más rápido, más eficiente), así que intente codificar las inserciones de forma tal que minimice los accesos a la base de datos. Recuerde que, a menos que use un grupo de conexiones, cada acceso al databse tiene que crear una conexión, ejecutar el sql y luego cortar la conexión. ¡Bastante un poco por encima!

Tu podrías querer :

  • Compruebe que la confirmación automática esté desactivada
  • Conexión abierta
  • Envíe varios lotes de inserciones en una sola transacción (¿tamaño de aproximadamente 4000-10000 filas?)
  • Conexión cercana

Dependiendo de qué tan bien se escale su servidor (está definitivamente bien con PostgreSQl , Oracle y MSSQL ), haga lo anterior con múltiples hilos y múltiples conexiones.

MYSQL 5.5 Una instrucción de inserción sql tomó ~ 300 a ~ 450 ms. mientras que las estadísticas a continuación son para enunciados de inserción múltiple en línea.

 (25492 row(s) affected) Execution Time : 00:00:03:343 Transfer Time : 00:00:00:000 Total Time : 00:00:03:343 

Yo diría que en línea es el camino a seguir 🙂

En general, las inserciones múltiples serán más lentas debido a la sobrecarga de conexión. Hacer varias inserciones a la vez reducirá el costo de la carga por inserción.

Dependiendo del idioma que esté utilizando, posiblemente pueda crear un lote en su lenguaje de progtwigción / scripting antes de ir a la base de datos y agregar cada inserción al lote. Entonces podría ejecutar un lote grande usando una operación de conexión. Aquí hay un ejemplo en Java.

La desactivación de las comprobaciones de restricciones hace que las inserciones sean mucho más rápidas. No importa que tu mesa lo tenga o no. Por ejemplo, prueba la desactivación de claves externas y disfruta de la velocidad:

 SET FOREIGN_KEY_CHECKS=0; 

Es ridículo lo malo que Mysql y MariaDB están optimizados cuando se trata de insertos. Probé mysql 5.7 y mariadb 10.3, sin diferencia real en esos.

Lo probé en un servidor con discos NVME, 70,000 IOPS, 1.1 GB / seg de rendimiento seq y es posible dúplex completo (lectura y escritura).
El servidor es un servidor de alto rendimiento también.
Le dio 20 GB de ram.
La base de datos está completamente vacía.

La velocidad que recibo es de 5000 inserciones por segundo cuando hago inserciones de varias filas (lo he intentado con 1MB hasta 10MB de datos)

Ahora la pista:
Si agrego otro hilo e inserto en las MISMAS tablas, de repente tengo 2×5000 / seg. Un hilo más y tengo 15000 en total / seg

Considere esto: Al hacer inserciones de UN hilo, significa que puede escribir secuencialmente en el disco (con excepciones a los índices). Al usar hilos, de hecho se degrada el rendimiento posible porque ahora necesita hacer muchos más accesos aleatorios. Pero la verificación de la realidad muestra que mysql está tan mal optimizado que los hilos ayudan mucho.

El rendimiento real posible con dicho servidor es probablemente de millones por segundo, la CPU está inactiva, el disco está inactivo.
La razón es bastante clara que mariadb igual que mysql tiene retrasos internos.

Intereting Posts