Tout ce qui suit s'applique à InnoDB.
Je pense que connaître les vitesses des 3 méthodes différentes est important.
Il existe 3 méthodes:
- INSÉRER: INSÉRER avec ON DUPLICATE KEY UPDATE
- TRANSACTION: où vous effectuez une mise à jour pour chaque enregistrement d'une transaction
- CAS: dans lequel vous avez un cas / quand pour chaque enregistrement différent dans une MISE À JOUR
Je viens de tester cela, et la méthode INSERT était de 6,7x plus rapide pour moi que la méthode TRANSACTION. J'ai essayé sur un ensemble de 3 000 et 30 000 lignes.
La méthode TRANSACTION doit toujours exécuter chaque requête individuellement, ce qui prend du temps, bien qu'elle traite les résultats en mémoire, ou quelque chose, lors de l'exécution. La méthode TRANSACTION est également assez coûteuse dans les journaux de réplication et de requête.
Pire encore, la méthode CASE était 41,1 fois plus lente que la méthode INSERT avec 30 000 enregistrements (6,1 fois plus lente que TRANSACTION). Et 75 fois plus lent dans MyISAM. Les méthodes INSERT et CASE ont même atteint environ 1 000 enregistrements. Même à 100 enregistrements, la méthode CASE est À peine plus rapide.
Donc, en général, je pense que la méthode INSERT est à la fois la meilleure et la plus facile à utiliser. Les requêtes sont plus petites et plus faciles à lire et ne prennent qu'une seule requête d'action. Cela s'applique à la fois à InnoDB et à MyISAM.
Trucs bonus:
La solution pour le problème INSERT non-champ par défaut est de désactiver temporairement les modes SQL pertinents: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Assurez-vous d'enregistrer le sql_mode
premier si vous prévoyez de le rétablir.
Quant aux autres commentaires que j'ai vus qui disent que l'auto_increment monte en utilisant la méthode INSERT, cela semble être le cas dans InnoDB, mais pas MyISAM.
Le code pour exécuter les tests est le suivant. Il génère également des fichiers .SQL pour supprimer la surcharge de l'interpréteur 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).';');
}