Semua hal berikut ini berlaku untuk InnoDB.
Saya merasa mengetahui kecepatan dari 3 metode yang berbeda itu penting.
Ada 3 metode:
- INSERT: INSERT dengan ON DUPLICATE KEY UPDATE
- TRANSAKSI: Di mana Anda melakukan pembaruan untuk setiap catatan dalam suatu transaksi
- KASUS: Di mana Anda case / kapan untuk setiap catatan yang berbeda dalam UPDATE
Saya baru saja menguji ini, dan metode INSERT 6,7x lebih cepat untuk saya daripada metode TRANSAKSI. Saya mencoba serangkaian 3.000 dan 30.000 baris.
Metode TRANSACTION masih harus menjalankan setiap permintaan secara individual, yang membutuhkan waktu, meskipun batch hasil dalam memori, atau sesuatu, saat mengeksekusi. Metode TRANSACTION juga cukup mahal untuk replikasi dan log permintaan.
Lebih buruk lagi, metode CASE adalah 41.1x lebih lambat dari metode INSERT dengan 30.000 catatan (6.1x lebih lambat dari TRANSACTION). Dan 75x lebih lambat di MyISAM. Metode INSERT dan CASE mencapai titik ~ 1.000 catatan Bahkan pada 100 catatan, metode KASUS BARELY lebih cepat.
Jadi secara umum, saya merasa metode INSERT adalah yang terbaik dan termudah untuk digunakan. Kueri lebih kecil dan lebih mudah dibaca dan hanya mengambil 1 kueri tindakan. Ini berlaku untuk InnoDB dan MyISAM.
Barang bonus:
Solusi untuk INSERT masalah non-default-bidang adalah untuk mematikan sementara mode SQL yang relevan: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Pastikan untuk menyimpan yang sql_mode
pertama jika Anda berencana untuk mengembalikannya.
Adapun komentar lain saya telah melihat bahwa mengatakan auto_increment naik menggunakan metode INSERT, ini tampaknya menjadi kasus di InnoDB, tetapi bukan MyISAM.
Kode untuk menjalankan tes adalah sebagai berikut. Ini juga menampilkan file .SQL untuk menghapus overhead penerjemah 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).';');
}