web-dev-qa-db-ja.com

MySQLでUPDATEクエリをバッチ処理する最も効率的な方法は何ですか?

大量の更新を長期間データベースにフラッシュする必要があるアプリケーションを作成していますが、クエリを最適化する方法に行き詰まっています。現在私は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;
10
jli

InnoDBテーブルを使用しているため、最も明らかな最適化は、複数のUPDATEsを1つのトランザクションにグループ化することです。

トランザクションエンジンであるInnoDBを使用すると、UPDATE自体だけでなく、トランザクションバッファー、トランザクションログの管理、ディスクへのログのフラッシュなど、すべてのトランザクションオーバーヘッドにも料金がかかります。

アイデアに論理的に慣れている場合は、一度に100〜1000個のUPDATEsをグループ化してみてください。

START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;

考えられる欠点:

  • 1つのエラーがトランザクション全体を折りたたみます(ただし、コードで簡単に修正できます)
  • 1000のUPDATEsが蓄積されるまで長時間待機する可能性があるため、タイムアウトを設定することもできます
  • アプリケーションコードがさらに複雑になります。
14
Shlomi Noach