Laravel, el límite INSERT de MySQL
Haciendo algunos DB Seeders surgió un problema porque estaba generando valores y almacenándolos en una matriz, luego insertándolos todos a la vez y luego el INSERT fallaría.
¡Hoy vamos a investigar qué limitaciones tiene!
Considere que tenemos la siguiente tabla:
Insertemos 1000 registros a la vez y veamos los resultados, nos detendremos en 100000 registros.
En el primer intento, se detuvo en 45k…
INSERTED: 1000 time(s): 0.0094678401947021
INSERTED: 2000 time(s): 0.011389970779419
INSERTED: 3000 time(s): 0.016204833984375
INSERTED: 4000 time(s): 0.022641897201538
…
INSERTED: 44000 time(s): 0.19947600364685
INSERTED: 45000 time(s): 0.28028988838196
FatalError: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2097160 bytes)
Lo comencé de nuevo y el punto de partida cambió de 1k a 64k
INSERTED: 46000 time(s): 0.22972512245178
INSERTED: 47000 time(s): 0.24145197868347
INSERTED: 48000 time(s): 0.21563100814819
…
INSERTED: 60000 time(s): 0.29563403129578
INSERTED: 61000 time(s): 0.2987060546875
INSERTED: 62000 time(s): 0.29574394226074
FatalError: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2097160 bytes)
Mismo problema. Es hora de deshabilitar mi límite de memoria de php.ini
FROM ; Maximum amount of memory a script may consume ; http://php.net/memory-limit memory_limit = 128MTO ; Maximum amount of memory a script may consume ; http://php.net/memory-limit memory_limit = -1
¡Probar el número tres!
INSERTED: 1000 time(s): 0.0098659992218018
INSERTED: 2000 time(s): 0.0082449913024902
INSERTED: 3000 time(s): 0.016316890716553
INSERTED: 4000 time(s): 0.020424127578735
…
INSERTED: 63000 time(s): 0.29119181632996
INSERTED: 64000 time(s): 0.31178092956543
INSERTED: 65000 time(s): 0.32407689094543
Y luego … fallar.
QueryException: SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders…
¡Parece que realmente hay un límite! Bien, busquemos entonces. Debería estar entre 65000 y 66000 registros en un INSERT.
Ahora los he repetido insertando 65010, 65020, 65030, y así sucesivamente hasta el primer fallo. Luego llegó al primer número significativo 65530. A partir de ahí he empezado a insertarlos uno por uno…
Y en la final, el límite de INSERT es: 65536 que en realidad es 2 elevado a 16
Idealmente, MySQL permite un número infinito de filas en una declaración INSERT, pero si MySQL Client recibe un paquete más grande que max_allowed_packet (65,636 bytes para MariaDB), arroja un error de paquete demasiado grande y termina la conexión.
Puede omitir esto haciendo esto:
SET GLOBAL max_allowed_packet=524288000; //bytes; SETS TO 500MB
O lo que sea que se adapte a sus necesidades, pero buscaría otras alternativas antes de hacer esto porque establece una configuración GLOBAL.