Todo lo siguiente se aplica a InnoDB.
Siento que conocer las velocidades de los 3 métodos diferentes es importante.
Hay 3 métodos:
- INSERTAR: INSERTAR CON ACTUALIZACIÓN DE LLAVE DUPLICADA
- TRANSACCIÓN: cuando realiza una actualización para cada registro dentro de una transacción
- CASO: en el cual usted es un caso / cuándo para cada registro diferente dentro de una ACTUALIZACIÓN
Acabo de probar esto, y el método INSERT fue 6.7 veces más rápido para mí que el método TRANSACTION. Probé en un conjunto de 3.000 y 30.000 filas.
El método TRANSACTION todavía tiene que ejecutar cada consulta individualmente, lo que lleva tiempo, aunque agrupa los resultados en la memoria, o algo así, mientras se ejecuta. El método de TRANSACCIÓN también es bastante costoso tanto en la réplica como en los registros de consultas.
Peor aún, el método CASE fue 41.1x más lento que el método INSERT con 30,000 registros (6.1x más lento que TRANSACTION). Y 75 veces más lento en MyISAM. Los métodos INSERT y CASE rompieron incluso a ~ 1,000 registros. Incluso con 100 registros, el método CASE es MUCHO más rápido.
Entonces, en general, creo que el método INSERT es el mejor y el más fácil de usar. Las consultas son más pequeñas y fáciles de leer y solo requieren 1 consulta de acción. Esto se aplica tanto a InnoDB como a MyISAM.
Cosas de bonificación:
La solución para el problema de la no-default-campo es INSERT para desactivar temporalmente los modos SQL pertinentes: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Asegúrese de guardar el sql_mode
primero si planea revertirlo.
En cuanto a otros comentarios que he visto que dicen que el auto_increment aumenta usando el método INSERT, este parece ser el caso en InnoDB, pero no en MyISAM.
El código para ejecutar las pruebas es el siguiente. También genera archivos .SQL para eliminar la sobrecarga del intérprete php
<?
//Variables
$NumRows=30000;
//These 2 functions need to be filled in
function InitSQL()
{
}
function RunSQLQuery($Q)
{
}
//Run the 3 tests
InitSQL();
for($i=0;$i<3;$i++)
RunTest($i, $NumRows);
function RunTest($TestNum, $NumRows)
{
$TheQueries=Array();
$DoQuery=function($Query) use (&$TheQueries)
{
RunSQLQuery($Query);
$TheQueries[]=$Query;
};
$TableName='Test';
$DoQuery('DROP TABLE IF EXISTS '.$TableName);
$DoQuery('CREATE TABLE '.$TableName.' (i1 int NOT NULL AUTO_INCREMENT, i2 int NOT NULL, primary key (i1)) ENGINE=InnoDB');
$DoQuery('INSERT INTO '.$TableName.' (i2) VALUES ('.implode('), (', range(2, $NumRows+1)).')');
if($TestNum==0)
{
$TestName='Transaction';
$Start=microtime(true);
$DoQuery('START TRANSACTION');
for($i=1;$i<=$NumRows;$i++)
$DoQuery('UPDATE '.$TableName.' SET i2='.(($i+5)*1000).' WHERE i1='.$i);
$DoQuery('COMMIT');
}
if($TestNum==1)
{
$TestName='Insert';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf("(%d,%d)", $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery('INSERT INTO '.$TableName.' VALUES '.implode(', ', $Query).' ON DUPLICATE KEY UPDATE i2=VALUES(i2)');
}
if($TestNum==2)
{
$TestName='Case';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf('WHEN %d THEN %d', $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery("UPDATE $TableName SET i2=CASE i1\n".implode("\n", $Query)."\nEND\nWHERE i1 IN (".implode(',', range(1, $NumRows)).')');
}
print "$TestName: ".(microtime(true)-$Start)."<br>\n";
file_put_contents("./$TestName.sql", implode(";\n", $TheQueries).';');
}