複数の単一のINSERTまたは1つの複数行のINSERTのどちらが速いですか?


184

MySQLにデータを挿入するコードの一部を最適化しようとしています。INSERTをチェーンして1つの巨大な複数行INSERTにするか、複数の個別のINSERTを高速化する必要がありますか?

回答:


287

https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html

行の挿入に必要な時間は、次の要因によって決まります。数値はおおよその比率を示します。

  • 接続中:(3)
  • サーバーにクエリを送信しています:(2)
  • 解析クエリ:(2)
  • 挿入行:(1×行サイズ)
  • インデックスの挿入:(1×インデックスの数)
  • 結び:(1)

これから明らかなように、1つの大きなステートメントを送信すると、挿入ステートメントごとに7のオーバーヘッドが節約されます。

同じクライアントから同時に多くの行を挿入する場合は、複数のVALUESリストを指定したINSERTステートメントを使用して、一度に複数の行を挿入します。これは、個別の単一行INSERTステートメントを使用するよりもかなり高速(場合によっては何倍も高速)です。


27
複数の単一のINSERTが同じデータベーストランザクション内にある場合、この回答はどのように適用されますか?
2015

2
単一の挿入ステートメントを使用して一度に挿入できる行数。一度に10000行を挿入できますか?
Naresh Ramoliya 2016

10
@ピンチ〜1.5kのアップサート(挿入/更新)を実行しながらトランザクションを使用すると、操作にかかる時間が〜1.5秒から〜0.2秒に短縮されました。つまり、単一行の挿入と比較して86%高速化されました。くそー。
fgblomqvist 2016年


反復的な複数の単一挿入を挿入するためにプリペアドステートメントを使用するのはどうですか
priyabagus

151

私はそれを頼まれたのほぼ2年半後にこの質問に答えるんだけど、私はちょうど今、実際に挿入ごとに複数の値ブロックをしている番組があることを私が働いているプロジェクトからいくつかのハードのデータを提供したかったMUCH連続する単一のVALUEブロックのINSERTステートメントよりも高速です。

C#でこのベンチマーク用に記述したコードは、ODBCを使用してMSSQLデータソースからデータをメモリに読み取り(約19,000行、すべて書き込みが始まる前にすべて読み取られます)、MySql .NETコネクタ(Mysql.Data。*)を使用して準備されたステートメントを介して、データをメモリからMySQLサーバーのテーブルに挿入します。これは、準備されたINSERTごとにVALUEブロックの数を動的に調整できるように記述されています(つまり、一度にn行を挿入し、実行前にnの値を調整できます)。テストも実行しました。各nに対して複数回。

単一のVALUEブロック(一度に1行など)を実行すると、実行に5.7〜5.9秒かかりました。その他の値は次のとおりです。

一度に2行:3.5-3.5秒一度に
5行:2.2-2.2秒一度に
10行:1.7-1.7秒一度に
50行:1.17-1.18秒一度に
100行:1.1-1.4 秒
一度に500行
:1.1-1.2 秒一度に1000行:1.17-1.17秒

つまり、2つまたは3つの書き込みをバンドルするだけでも、n = 5とn = 10の間のどこかに到達するまで、速度が劇的に向上します(実行時間はn分の1に短縮されます)。そして、n = 10からn = 50の範囲のどこかで、改善は無視できるほどになります。

(a)multiprepareのアイデアを使用するかどうか、および(b)ステートメントごとに作成するVALUEブロックの数を決定するのに役立つことを願っています(最大のクエリサイズを超えてクエリをプッシュするのに十分な大きさのデータを操作する場合) MySQLの場合、多くの場所でデフォルトで16MBであると私は考えています。サーバーに設定されたmax_allowed_pa​​cketの値に応じて、これより大きくまたは小さくなる可能性があります。)


1
明確化要求:時間は「行あたりの秒数」または「合計秒数」です。
EngrStudent 2015

3
合計秒数-行あたりの秒数は、約19,000行で割ったものです。これは小さい数値ですが、簡単に比較できる数値を探している場合は、おそらく行/秒がより良いメトリックになります。
Jon Kloske 2015

ちなみに、私は私のこの関連答えに上述のアプローチのためのいくつかの例の.NETコードがあります:stackoverflow.com/questions/25377357/...
ジョンKloske

18

主な要因は、トランザクションエンジンを使用しているかどうか、および自動コミットをオンにしているかどうかです。

自動コミットはデフォルトでオンになっており、おそらくオンのままにしたいでしょう。したがって、実行する挿入ごとに独自のトランザクションが実行されます。つまり、行ごとに1つの挿入を行うと、各行のトランザクションをコミットすることになります。

シングルスレッドと仮定すると、サーバーはすべての行について、一部のデータをディスクに同期する必要があります。データが永続的なストレージの場所に到達するまで待つ必要があります(できれば、RAIDコントローラーのバッテリーバックアップされたRAM)。これは本質的にかなり遅く、おそらくこれらの場合の制限要因になるでしょう。

もちろん、トランザクショナルエンジン(通常はinnodb)を使用していて、耐久性を下げるために設定を微調整していないことを前提としています。

また、これらの挿入を行うために単一のスレッドを使用していると想定しています。MySQLの一部のバージョンではinnodbにワーキンググループコミットがあるため、複数のスレッドを使用すると多少問題が生じます-これは、独自のコミットを実行する複数のスレッドがトランザクションログへの単一の書き込みを共有できることを意味します。 。

一方、結果として、複数行の挿入を本当に使用したいということです。

逆効果になる制限はありますが、ほとんどの場合、10,000行以上です。したがって、それらを1,000行までバッチ処理する場合は、おそらく安全です。

MyISAMを使用している場合は、他にもたくさんのことがありますが、それらに飽きることはありません。平和。


1
ポイント後に逆効果になる理由はありますか?私もそれが起こるのを見たことがありますが、その理由はわかりませんでした。
Dhruv Gairola 2013

1
トランザクションを使用するときにMySQL挿入のバッチ処理に何かポイントがあるかどうかを知っていますか。基になるライブラリ(Java JDBC-mysql-connector-java-5.1.30)が実際にコミットしない限り、多値SQLコマンドを生成しなければならないという手間を省くことができるかどうか疑問に思っています。
RTF

@RTFこれは実装固有の動作であるため、状況でその動作を判別するには小さなテストを実行する必要があると思いますが、多くの場合、トランザクションは同様のパフォーマンス向上をもたらすはずです。
ジャスミンヘグマン

9

できるだけ多くのインサートを一度にワイヤに送信します。実際の挿入速度は同じでなければなりませんが、ネットワークオーバーヘッドの削減によりパフォーマンスが向上します。


7

一般に、データベースへの呼び出し回数が少ないほど良い(より速く、より効率的であることを意味する)ため、データベースアクセスを最小限に抑えるような方法で挿入をコーディングしてください。接続プールを使用していない限り、各データベースアクセスで接続を作成し、SQLを実行して、接続を破棄する必要があることに注意してください。かなりのオーバーヘッド!


永続的な接続が使用されている場合はどうなりますか?
dusoft 2009年

6
まだオーバーヘッドがあります。何千回もの挿入を行っている場合、通過時間だけで(個別の挿入ごとに往復)、すぐに認識できます。
RC。

4

あなたは望むかもしれない :

  • 自動コミットがオフになっていることを確認してください
  • 接続を開く
  • 単一のトランザクションで複数の挿入バッチを送信します(サイズは約4000〜10000行ですか?わかります)
  • 接続を閉じる

サーバーがどれだけ適切にスケーリングするかに応じて(サーバーはPostgreSQlOracleおよびで間違いなくMSSQL問題ありません)、複数のスレッドと複数の接続で上記のことを行います。


3

一般に、接続のオーバーヘッドのため、複数の挿入は遅くなります。一度に複数の挿入を行うと、挿入ごとのオーバーヘッドのコストが削減されます。

使用している言語によっては、dbに移動する前にプログラミング/スクリプト言語でバッチを作成し、各挿入をバッチに追加できます。その後、1つの接続操作を使用して大きなバッチを実行できます。ここだ Javaでの例では。


3

MYSQL 5.5 1つのSQL挿入ステートメントは、約300ミリ秒から最大450ミリ秒かかりました。一方、以下の統計はインラインの複数挿入ステートメント用です。

(25492 row(s) affected)
Execution Time : 00:00:03:343
Transfer Time  : 00:00:00:000
Total Time     : 00:00:03:343

私はインラインが行く方法だと思います:)


0

挿入に関して、MysqlとMariaDBがどのように最適化されるかはばかげています。私はmysql 5.7とmariadb 10.3をテストしましたが、実際の違いはありません。

NVMEディスク、70,000 IOPS、1.1 GB /秒のseqスループットを備えたサーバーでこれをテストしましたが、これは全二重(読み取りと書き込み)の可能性があります。
サーバーも高性能サーバーです。
20 GBのRAMを割り当てます。
データベースは完全に空です。

私が受け取る速度は、複数行の挿入を実行するときに1秒あたり5000挿入でした(1 MBから最大10 MBのデータチャンクで試行しました)。

今手がかり:
別のスレッドを追加して同じテーブルに挿入すると、突然2x5000 /秒になります。もう1つのスレッドと私は合計15000 /秒

次のことを考慮してください。1つのスレッド挿入を実行する場合は、ディスクに順次書き込むことができます(インデックスを除く)。スレッドを使用する場合、ランダムアクセスをより多く実行する必要があるため、実際には可能なパフォーマンスが低下します。しかし、現実性チェックは、mysqlが非常に不適切に最適化されていることを示しており、スレッドは非常に役立ちます。

このようなサーバーで可能な実際のパフォーマンスは1秒あたり数百万です。CPUはアイドル状態で、ディスクはアイドル状態です。
その理由は、mysqlに内部遅延があるのとまったく同じようにmariadbがあることは明らかです。


@Craftables外部開発が必要な場合、mysql内では実行できません。スレッドとは、サーバーへの複数の接続を使用し、クエリを複数のチャンクに分割することを意味します(たとえば、主キーによってクエリを偶数の部分に分割することにより)。非常に大きなテーブルでこのメソッドを使用すると、最大で10,000倍のパフォーマンスが得られました。複数のスレッドを使用し、mysqlが高度に最適化されている場合、40,000秒実行されるクエリは2〜3分で終了します。
ジョン

@John興味深いし、いくつかの本当の素晴らしいアプリケーションがあるかもしれません...しかし...クエリを複数のチャンクに分割する場合、トランザクションをどのように処理しますか?また、次のシナリオも検討してください。テーブルxには、同じテーブル「id」に関連する「parent_id」列があります。データのどこかにINSERT INTO x(idparent_id)VALUES(1、NULL)があります。次の値のセットの1つがその行にリンクしています。チャンクに分割し、そのセットが別のチャンクに到達すると、最初のチャンクの前に処理され、プロセス全体が失敗する場合があります。それに対処する方法はありますか?
zozo

@zozoこれは、一括挿入と一括クエリに役立ちます。トランザクションには、大量のデータバッファリングが含まれているため、いずれにしてもパフォーマンスが低下します。ただし、マルチスレッドの挿入またはクエリでトランザクションを使用することもできます。
ジョン

-2

複数の挿入はより高速ですが、それは回避すべきです。別のスリックは、制約チェックを無効にして、一時的な挿入をはるかに高速に行います。テーブルにあるかどうかは関係ありません。たとえば、外部キーの無効化をテストしてスピードを楽しんでください:

SET FOREIGN_KEY_CHECKS=0;

もちろん、次の方法で挿入後にオンにする必要があります。

SET FOREIGN_KEY_CHECKS=1;

これは、巨大なデータを挿入する一般的な方法です。データの整合性が失われる可能性があるため、外部キーのチェックを無効にする前に注意が必要です。


1
なぜpplがこれを2つの理由で賛成したのかわかりません。1。質問とは何の関係もありません。2。本当に悪いアイデアです(いくつかの例外-ダンプや構造の一時的な変更など-が一般的には悪い)。チェックは理由があります。データの整合性を確保するためにあります。それらはあなたがすべきでないデータを挿入したり変更したりしないことを保証するために物事を遅くします。正しい方法でクエリを最適化してください。どのようなビジネスクリティカルな環境でも、これはアプリが停止することを意味します。
zozo

1
たぶん、このオプションは大きなテーブルのインポートに非常に効果的で非常に実用的であり、データの挿入をはるかに高速化する方法を知っている人もいるでしょう。
MSS、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.