Estoy tratando de optimizar una parte de mi código que inserta datos en MySQL. ¿Debo encadenar INSERT para hacer un enorme INSERT de varias filas o son varios INSERT separados más rápido?
fuente
Estoy tratando de optimizar una parte de mi código que inserta datos en MySQL. ¿Debo encadenar INSERT para hacer un enorme INSERT de varias filas o son varios INSERT separados más rápido?
https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html
El tiempo requerido para insertar una fila está determinado por los siguientes factores, donde los números indican proporciones aproximadas:
- Conexión: (3)
- Enviando consulta al servidor: (2)
- Consulta de análisis: (2)
- Insertar fila: (1 × tamaño de fila)
- Insertar índices: (1 × número de índices)
- Clausura: (1)
A partir de esto, debería ser obvio que enviar una declaración grande le ahorrará una sobrecarga de 7 por instrucción de inserción, que en una lectura posterior del texto también dice:
Si está insertando muchas filas desde el mismo cliente al mismo tiempo, use instrucciones INSERT con múltiples listas de VALORES 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 de una sola fila por separado.
Sé que estoy respondiendo esta pregunta casi dos años y medio después de que se hizo, pero solo quería proporcionar algunos datos concretos de un proyecto en el que estoy trabajando en este momento que muestra que, de hecho, hacer varios bloques de VALOR por inserción es MUCHO más rápido que las instrucciones INSERT de bloque 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 la escritura), y el conector MySql .NET (Mysql.Data. *) INSERTE los datos de la memoria en una tabla en un servidor MySQL a través de declaraciones preparadas. Fue escrito de tal manera que me permite ajustar dinámicamente el número de bloques de VALOR por INSERTAR 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 bloques de VALOR individuales (por ejemplo, 1 fila a la vez) tardó 5,7 - 5,9 segundos en 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
Entonces, sí, incluso agrupar 2 o 3 escrituras juntas proporciona una mejora dramática en la velocidad (tiempo de ejecución cortado por un factor de n), hasta llegar a algún lugar entre n = 5 y n = 10, momento en el cual la mejora disminuye notablemente, y en algún lugar en el rango n = 10 a n = 50 la mejora se vuelve insignificante.
Espero que ayude a las personas a decidir sobre (a) si usar la idea de reparación múltiple y (b) cuántos bloques de VALOR crear por declaración (suponiendo que desee trabajar con datos que pueden ser lo suficientemente grandes como para llevar la consulta más allá del 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 dependiendo del valor de max_allowed_packet establecido en el servidor).
fuente
Un factor importante será si está utilizando un motor transaccional y si tiene la confirmación automática activada.
La confirmación automática está activada de manera predeterminada y probablemente desee dejarla activada; por lo tanto, cada inserción que realice hace su propia transacción. Esto significa que si realiza una inserción por fila, va a confirmar una transacción para cada fila.
Suponiendo un solo subproceso, eso significa que el servidor necesita sincronizar algunos datos en el disco por CADA FILA. Debe esperar a que los datos lleguen a una ubicación de almacenamiento persistente (es de esperar que la memoria RAM respaldada por batería en su controlador RAID). Esto es inherentemente lento y probablemente se convertirá en el factor limitante en estos casos.
Por supuesto, supongo que está utilizando un motor transaccional (generalmente innodb) Y que no ha modificado la configuración para reducir la durabilidad.
También supongo que está utilizando un solo hilo para hacer estas inserciones. El uso de varios subprocesos enturbia un poco las cosas porque algunas versiones de MySQL tienen un compromiso de trabajo grupal en innodb; esto significa que varios subprocesos que realizan sus propios compromisos pueden compartir una sola escritura en el registro de transacciones, lo cual es bueno porque significa menos sincronizaciones con el almacenamiento persistente .
Por otro lado, el resultado es que REALMENTE DESEA USAR insertos de varias filas.
Hay 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 las agrupa hasta 1,000 filas, probablemente esté seguro.
Si está utilizando MyISAM, hay muchas otras cosas, pero no lo aburriré con eso. Paz.
fuente
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á ganancias de rendimiento por la reducción de la sobrecarga de la red.
fuente
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 tal manera que minimice los accesos a la base de datos. Recuerde, a menos que esté utilizando un grupo de conexiones, cada acceso a la base de datos debe crear una conexión, ejecutar el sql y luego cortar la conexión. ¡Un poco de gastos generales!
fuente
Tu podrías querer :
Dependiendo de qué tan bien escale su servidor (definitivamente está bien con
PostgreSQl
,Oracle
yMSSQL
), haga lo anterior con múltiples hilos y múltiples conexiones.fuente
En general, las inserciones múltiples serán más lentas debido a la sobrecarga de la conexión. Hacer múltiples inserciones a la vez reducirá el costo de sobrecarga por inserción.
Dependiendo del idioma que esté utilizando, posiblemente pueda crear un lote en su lenguaje de programación / scripting antes de ir a la base de datos y agregar cada inserción al lote. Entonces podrá ejecutar un lote grande utilizando una operación de conexión. Aquí hay un ejemplo en Java.
fuente
MYSQL 5.5 Una instrucción de inserción sql tomó ~ 300 a ~ 450ms. mientras que las estadísticas a continuación son para declaraciones de inserción múltiple en línea.
Yo diría que en línea es el camino a seguir :)
fuente
Es ridículo lo mal que Mysql y MariaDB están optimizados cuando se trata de inserciones. Probé mysql 5.7 y mariadb 10.3, no hay diferencia real en esos.
He probado esto en un servidor con discos NVME, 70,000 IOPS, 1,1 GB / seg de rendimiento seq y eso es posible full duplex (lectura y escritura).
El servidor también es un servidor de alto rendimiento.
Le dio 20 GB de ram.
La base de datos está completamente vacía.
La velocidad que recibo fue de 5000 inserciones por segundo al hacer inserciones de varias filas (lo probé con fragmentos de datos de 1 MB hasta 10 MB)
Ahora la pista:
si agrego otro hilo e inserto en las MISMAS tablas, de repente tengo 2x5000 / seg. Un hilo más y tengo 15000 totales / seg.
Considere esto: cuando se inserta ONE thread, significa que puede escribir secuencialmente en el disco (con excepción de los índices). Cuando se usan subprocesos, en realidad degrada el rendimiento posible porque ahora necesita hacer muchos más accesos aleatorios. Pero la comprobació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 y el disco está inactivo.
La razón es claramente que mariadb al igual que mysql tiene retrasos internos.
fuente
id
,parent_id
) VALUES (1, NULL). Uno de los siguientes conjuntos de valores enlaza con esa fila. Si se divide en fragmentos y ese conjunto llega a otro fragmento, puede procesarse antes del primero, fallando todo el proceso. ¿Alguna idea de cómo lidiar con eso?las inserciones múltiples son más rápidas, pero se debe haber. otro truco es deshabilitar las restricciones, los controles temporales hacen que las inserciones sean mucho más rápidas. No importa que tu mesa lo tenga o no. Por ejemplo, pruebe deshabilitar claves externas y disfrute de la velocidad:
por supuesto, debe volver a encenderlo después de las inserciones:
Esta es una forma común de insertar grandes datos. la integridad de los datos puede romperse, por lo que debe preocuparse por eso antes de deshabilitar las comprobaciones de claves externas.
fuente