Aşağıdakilerin tümü InnoDB için geçerlidir.
3 farklı yöntemin hızını bilmek önemlidir.
3 yöntem vardır:
- INSERT: ON DUPLICATE KEY UPDATE ile ekle
- İŞLEM: Bir işlemdeki her kayıt için güncelleme yaptığınız yer
- DURUM: Bir GÜNCELLEME içindeki her farklı kayıt için bir vaka / ne zaman
Bunu yeni test ettim ve INSERT yöntemi benim için TRANSACTION yönteminden 6,7 kat daha hızlıydı. Hem 3.000 hem de 30.000 satırlık bir dizi denedim.
TRANSACTION yöntemi, yürütme sırasında sonuçları bellekte veya başka bir şeyde topluyor olsa da, her bir tek sorguyu çalıştırmaya devam etmelidir. TRANSACTION yöntemi hem çoğaltma hem de sorgu günlüklerinde oldukça pahalıdır.
Daha da kötüsü, VAKA yöntemiydi 41.1x / 30.000 kayıtları (daha yavaş İŞLEM daha 6.1x) w yavaş INSERT yönteminden daha. Ve MyISAM'de 75 kat daha yavaş. INSERT ve CASE yöntemleri ~ 1000 kayıtta bile kırıldı. 100 kayıtta bile, CASE yöntemi BARELY'dir.
Genel olarak, INSERT yönteminin hem en iyi hem de kullanımı en kolay olduğunu düşünüyorum. Sorgular daha küçüktür ve okunması daha kolaydır ve yalnızca 1 işlem sorgusunu alır. Bu hem InnoDB hem de MyISAM için geçerlidir.
Bonus şeyler:
INSERT varsayılan olmayan alan sorununa çözüm geçici olarak ilgili SQL modlarını kapatmak olur: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Geri sql_mode
döndürmeyi planlıyorsanız ilkini kaydettiğinizden emin olun .
Auto_increment'in INSERT yöntemini kullanarak arttığını söyleyen diğer yorumlara gelince, bu InnoDB'de olduğu gibi görünüyor, ancak MyISAM değil.
Testleri yapmak için kod aşağıdaki gibidir. Ayrıca php yorumlayıcı yükünü kaldırmak için .SQL dosyaları çıkarır
<?
//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).';');
}