MySQL の UPDATE 文は書き方でパフォーマンスが変わる
Posted on
MySQL で別テーブルのデータを使って UPDATE するには、JOIN を使うほかに MySQL 独自の書き方ができます。
UPDATE table_foo, table_bar
SET table_foo.name = table_bar.name
WHERE table_foo.id = table_bar.id;
UPDATE 句の後に更新したいテーブルと参照したいテーブルを並べて内部結合します。 INNER JOIN や LEFT JOIN に比べるとシンプルに書けるので、この書き方を好んで使っていました。
今回、数百万レコードを対象に UPDATE するバッチ処理を書いていると、どうもこの SQL がボトルネックになっていることが分かりました。ためしに INNER JOIN に変えてみると実行時間が短縮されました。
UPDATE table_foo
INNER JOIN table_bar
ON table_foo.id = table_bar.id
SET table_foo.name = table_bar.name
WHERE table_foo.id = table_bar.id;
検証してみた
MySQL 5.1 系と 5.5 系を使って検証してみました。
- 5, 10, 20, 40 万レコードのダミーデータを使用
- LOAD DATA INFILE を使って CSV ファイルからインポート
- 計測ごとに全テーブルを TRUNCATE
- ストレージエンジンは InnoDB
まず MySQL 5.1 の結果です。 20 万までは MySQL 独自の書き方が速いですが、40 万を超えると 0.5 秒以上の差をつけて INNER JOIN が逆転します。
MySQL 独自 | INNER JOIN | |
---|---|---|
50,000 | 1.30 sec | 1.34 sec |
100,000 | 2.61 sec | 3.01 sec |
200,000 | 4.70 sec | 5.33 sec |
400,000 | 9.04 sec | 8.37 sec |
次に MySQL 5.5 の結果です。同じ SQL なのに 5.1 と比べて大幅に改善されていることがわかります。こちらも 20 万を超えると僅差ですが INNER JOIN が逆転しました。
MySQL 独自 | INNER JOIN | |
---|---|---|
50,000 | 0.36 sec | 0.40 sec |
100,000 | 0.58 sec | 0.59 sec |
200,000 | 1.58 sec | 1.32 sec |
400,000 | 2.87 sec | 2.56 sec |
バージョンに関わらず、数百万レコードを扱うときは JOIN を使った結合が速くなるようです。先日リリースされた MySQL 5.6 では InnoDB がさらに改善されたそうなので、この結果も変わってくるかもしれません。