大量の更新を長期間データベースにフラッシュする必要があるアプリケーションを作成していますが、クエリを最適化する方法に行き詰まっています。現在私はINSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE
を使用しています。これは、すべての値を1つのクエリにバッチ処理するように機能しますが、大きなテーブルでは非常に遅く実行されます。実際に行を挿入する必要はありません。
私が見た他のアプローチは、SET value = CASE WHEN...
を使用して更新することです(クエリを構築する方法が原因で生成するのは難しく、CASE
のパフォーマンスについてはわかりません数百/数千のキー)、および単純に複数の連結された更新。これらのどちらが私の現在の方法よりも速いでしょうか?
私の知る限り、MySQLでこれを行うための慣用的で効率的な方法はないことに戸惑います。 ON DUPLICATE KEY
よりも高速な方法が本当にない場合、PostgreSQLに切り替えてUPDATE FROM
構文を使用する価値はありますか?
他の提案も大歓迎です!
編集:頻繁に更新されるテーブルの1つを次に示します。無関係であるため、列名を削除しました。
CREATE TABLE IF NOT EXISTS `table` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`a` bigint(20) unsigned NOT NULL DEFAULT '0',
`b` bigint(20) unsigned NOT NULL DEFAULT '0',
`c` enum('0','1','2') NOT NULL DEFAULT '0',
`d` char(32) NOT NULL,
-- trimmed --
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`),
KEY `c` (`c`),
KEY `d` (`d`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
InnoDB
テーブルを使用しているため、最も明らかな最適化は、複数のUPDATE
sを1つのトランザクションにグループ化することです。
トランザクションエンジンであるInnoDB
を使用すると、UPDATE
自体だけでなく、トランザクションバッファー、トランザクションログの管理、ディスクへのログのフラッシュなど、すべてのトランザクションオーバーヘッドにも料金がかかります。
アイデアに論理的に慣れている場合は、一度に100〜1000個のUPDATE
sをグループ化してみてください。
START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;
考えられる欠点:
UPDATE
sが蓄積されるまで長時間待機する可能性があるため、タイムアウトを設定することもできます