Für InnoDB gilt Folgendes.
Ich halte es für wichtig, die Geschwindigkeit der drei verschiedenen Methoden zu kennen.
Es gibt 3 Methoden:
- INSERT: INSERT mit ON DUPLICATE KEY UPDATE
- TRANSAKTION: Hier führen Sie eine Aktualisierung für jeden Datensatz innerhalb einer Transaktion durch
- FALL: In welchem Fall / wann Sie für jeden unterschiedlichen Datensatz innerhalb eines UPDATE einen Fall / wann
Ich habe das gerade getestet und die INSERT-Methode war für mich 6,7-mal schneller als die TRANSACTION-Methode. Ich habe sowohl 3.000 als auch 30.000 Zeilen ausprobiert.
Die TRANSACTION-Methode muss weiterhin jede einzelne Abfrage ausführen, was einige Zeit in Anspruch nimmt, obwohl sie die Ergebnisse während der Ausführung im Speicher oder so stapelt. Die TRANSACTION-Methode ist sowohl in Replikations- als auch in Abfrageprotokollen ziemlich teuer.
Schlimmer noch, die CASE-Methode war 41,1-mal langsamer als die INSERT-Methode mit 30.000 Datensätzen (6,1-mal langsamer als TRANSACTION). Und 75x langsamer in MyISAM. Die INSERT- und CASE-Methoden haben bei ~ 1.000 Datensätzen die Gewinnschwelle überschritten. Selbst bei 100 Datensätzen ist die CASE-Methode kaum schneller.
Im Allgemeinen halte ich die INSERT-Methode für die beste und einfachste Anwendung. Die Abfragen sind kleiner und leichter zu lesen und nehmen nur eine Aktionsabfrage auf. Dies gilt sowohl für InnoDB als auch für MyISAM.
Bonusmaterial:
Die Lösung für das Problem des INSERT-Nicht-Standardfelds besteht darin, die relevanten SQL-Modi vorübergehend auszuschalten : SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Stellen Sie sicher, sql_mode
dass Sie die erste speichern, wenn Sie sie zurücksetzen möchten.
Was andere Kommentare betrifft, die besagen, dass das auto_increment mit der INSERT-Methode hochgefahren wird, scheint dies in InnoDB der Fall zu sein, nicht jedoch in MyISAM.
Der Code zum Ausführen der Tests lautet wie folgt. Es gibt auch .SQL-Dateien aus, um den Overhead des PHP-Interpreters zu beseitigen
<?
//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).';');
}