Tutto ciò che segue si applica a InnoDB.
Sento che conoscere le velocità dei 3 diversi metodi è importante.
Esistono 3 metodi:
- INSERISCI: INSERIRE con AGGIORNAMENTO CHIAVE SU DUPLICATO
- TRANSAZIONE: dove si esegue un aggiornamento per ciascun record all'interno di una transazione
- CASO: in cui è un caso / quando per ogni record diverso all'interno di un AGGIORNAMENTO
Ho appena provato questo, e il metodo INSERT è stato 6,7 volte più veloce per me rispetto al metodo TRANSACTION. Ho provato su un set di 3.000 e 30.000 righe.
Il metodo TRANSACTION deve ancora eseguire ogni query individualmente, il che richiede tempo, sebbene in batch i risultati in memoria o qualcosa del genere, durante l'esecuzione. Il metodo TRANSAZIONE è anche piuttosto costoso sia nei registri di replica che di query.
Ancora peggio, il metodo CASE era 41.1x più lento del metodo INSERT con 30.000 record (6.1x più lento di TRANSAZIONE). E 75 volte più lento in MyISAM. I metodi INSERT e CASE hanno battuto anche a ~ 1.000 record. Anche a 100 record, il metodo CASE è MOLTO più veloce.
Quindi, in generale, ritengo che il metodo INSERT sia il migliore e più facile da usare. Le query sono più piccole e più facili da leggere e richiedono solo 1 query di azione. Questo vale sia per InnoDB che per MyISAM.
Bonus:
La soluzione per il problema della non-default-campo INSERT è quello di disattivare temporaneamente le modalità SQL rilevanti: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Assicurati di salvare il sql_mode
primo se prevedi di ripristinarlo.
Come per altri commenti, ho visto che dire che auto_increment sale usando il metodo INSERT, questo sembra essere il caso di InnoDB, ma non di MyISAM.
Il codice per eseguire i test è il seguente. Emette anche file .SQL per rimuovere l'overhead dell'interprete 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).';');
}