以下はすべて InnoDB に適用されます。
3つの異なる方法の速度を知ることは重要だと感じています.
3 つの方法があります。
- INSERT: ON DUPLICATE KEY UPDATE を使用した INSERT
- TRANSACTION: トランザクション内の各レコードの更新を行う場所
- CASE: UPDATE 内の異なるレコードごとにケース/いつ
これをテストしたところ、INSERT メソッドはTRANSACTION メソッドよりも 6.7 倍高速でした。3,000 行と 30,000 行の両方のセットを試しました。
TRANSACTION メソッドは、実行中に結果をメモリなどにバッチ処理しますが、それぞれのクエリを個別に実行する必要があります。これには時間がかかります。TRANSACTION メソッドも、レプリケーションとクエリ ログの両方でかなりコストがかかります。
さらに悪いことに、CASE メソッドは、 30,000 レコードの INSERT メソッドよりも41.1倍遅くなりました (TRANSACTION よりも 6.1 倍遅い)。MyISAMでは75倍遅くなります。INSERT メソッドと CASE メソッドは、レコード数が 1,000 まででも壊れました。100 レコードでも、CASE メソッドはかろうじて高速です。
したがって、一般的には、INSERT メソッドが最適で使いやすいと思います。クエリは小さくて読みやすく、アクションのクエリは 1 つだけです。これは InnoDB と MyISAM の両方に当てはまります。
ボーナス要素:
INSERT 非デフォルト フィールドの問題の解決策は、関連する SQL モードを一時的にオフにすることですSET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
。sql_mode
元に戻す予定がある場合は、必ず最初のものを保存してください。
auto_increment が INSERT メソッドを使用して上昇するという他のコメントについては、これは InnoDB では当てはまりますが、MyISAM では当てはまらないようです。
テストを実行するコードは次のとおりです。また、.SQL ファイルを出力して、php インタープリターのオーバーヘッドを取り除きます。
<?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).';');
}