MySQLのベストプラクティス-データを効率的に挿入する

MySQLデータベースにバッチで数百万のデータを挿入する必要がある場合、INSERTステートメントを1つずつ送信することは現実的な方法ではないことに気付くでしょう。

MySQLのドキュメントで読む価値のあるINSERT最適化のヒントがいくつかあります。

この記事では、MySQLデータベースにデータを効率的にロードするための2つの手法の概要を説明します。

データファイルの読み込み

元のパフォーマンスを改善するソリューションを探しているなら、これが間違いなく最初の選択肢です。LOAD DATA INFILEは、MySQL専用の高度に最適化されたステートメントであり、CSV / TSVファイルのデータをテーブルに直接挿入します。

LOAD DATA INFILEを使用するには2つの方法があります。データファイルをサーバーのデータディレクトリ(通常は/ var / lib / mysql-files /)にコピーして実行します。

LOAD DATA INFILE '/path/to/products.csv' INTO TABLE products;

この方法は非常に面倒です。サーバーのファイルシステムにアクセスしたり、データファイルに適切な権限を設定したりする必要があるためです。

良いニュースは、クライアントにデータファイルを保存して、LOCALキーワードを使用することもできるということです。

LOAD DATA LOCAL INFILE '/path/to/products.csv' INTO TABLE products;

この場合、クライアントファイルシステムからファイルを読み取り、サーバー側の一時ディレクトリに透過的にコピーしてから、ディレクトリからインポートします。全体として、これはサーバーのファイルシステムからファイルを直接ロードするのとほぼ同じくらい高速ですが、サーバーでこのオプションが有効になっていることを確認する必要があります。

LOAD DATA INFILEには多くのオプションがあり、主にデータファイルの構造(フィールドセパレーター、添付ファイルなど)に関連しています。完全なコンテンツを確認するには、ドキュメントを参照してください。

パフォーマンスの観点からは、LOAD DATA INFILEが最良のオプションですが、この方法では、最初にデータをコンマ区切り形式でテキストファイルにエクスポートする必要があります。このようなファイルがない場合は、追加のリソースを使用してファイルを作成する必要があり、アプリケーションの複雑さがある程度増える可能性があります。幸い、別のオプションがあります。

拡張インサート(拡張インサート)

典型的なINSERT SQLステートメントは次のようになります。

INSERT INTO user (id, name) VALUES (1, 'Ben');

拡張INSERTは、挿入された複数のレコードを1つのクエリステートメントに集約します。

INSERT INTO user (id, name) VALUES (1, 'Ben'), (2, 'Bob');

重要なのは、各ステートメントに挿入する最適なレコード数を見つけることです。万能の数値はありません。そのため、データサンプルをベンチマークして、最大のパフォーマンスゲインを見つけるか、メモリ使用量とパフォーマンスの最適な妥協点を見つける必要があります。

拡張インサートを最大限に活用するために、以下もお勧めします。

  • 準備されたステートメントを使用する
  • トランザクションでステートメントを実行する

ベンチマーク

120万件のレコードを挿入したいのですが、各レコードは6種類の混合データで構成されており、各データのサイズは約26バイトです。テストには2つの一般的な構成を使用しました。

  • クライアントとサーバーは同じマシン上にあり、UNIXソケットを介して通信します
  • クライアントとサーバーは異なるマシン上にあり、非常に低いレイテンシ(0.1ミリ秒未満)でギガビットネットワークを介して通信します

比較の基準として、INSERT ... SELECTを使用してテーブルをコピーしました。この操作のパフォーマンスは、1秒あたり313,000データを挿入していました。

データファイルの読み込み

驚いたことに、テスト結果は、LOAD DATA INFILEがテーブルのコピーよりも速いことを証明しています。

  • データファイルの読み込み:1秒あたり377,000挿入
  • ネットワークを介してデータローカルINFILEをロード:322,000挿入/秒

これら2つの数値の違いは、クライアントからサーバーにデータを転送するのにかかる時間に直接関係しているようです。データファイルのサイズは53 MB、2つのベンチマークの時間差は543ミリ秒です。つまり、伝送速度は780 Mbpsです。ギガビット速度に近い。

これは、ファイルが完全に転送される前に、MySQLサーバーがファイルの処理を開始しない可能性が非常に高いことを意味します。したがって、挿入の速度は、クライアントとサーバー間の帯域幅に直接関係します(同じマシン上にない場合)。これは非常に重要です。

拡張インサート

BulkInserterを使用して挿入の速度をテストします。BulkInserterは、私が作成したオープンソースライブラリのPHPクラスの一部であり、各クエリは最大10,000レコードを挿入できます。

 

[翻訳] MySQLのベストプラクティス-効率的なデータ挿入

 

 

これまで見てきたように、クエリごとの挿入数が増えると、挿入速度も急速に増加します。1つずつ挿入する速度と比較して、ローカルホストで6倍、ネットワークホストで17倍のパフォーマンスが向上しました。

  • ローカルホストでの挿入数を1秒あたり40,000から247,000に増加
  • Webホストでの1秒あたりの挿入数が1,2000から201,000に増加

どちらの場合も、最大のスループットを実現するには、クエリごとに約1,000の挿入が必要です。ただし、クエリごとに40回の挿入を行うと、ローカルホストで90%のスループットを達成できます。ピークに達した後、クエリあたりの挿入数が増えると、実際にはパフォーマンスが低下することにも注意してください。

連続挿入の速度はネットワークの遅延に依存するため、拡張挿入の利点はネットワーク接続の場合により明白です。

max sequential inserts per second ~= 1000 / ping in milliseconds

クライアントとサーバー間の遅延が大きいほど、拡張挿入のメリットが大きくなります。

おわりに

予想通り、LOAD DATA INFILEは、単一の接続でパフォーマンスを向上させるための推奨ソリューションです。正しい形式でファイルを準備する必要があります。最初にこのファイルを生成するか、データベースサーバーに転送する必要がある場合は、挿入速度をテストするときに、このプロセスの時間消費を考慮する必要があります。

一方、拡張挿入は一時テキストファイルを必要とせず、非常に妥当な挿入速度であるLOAD DATA INFILEの65%に相当するスループットを達成できます。興味深いことに、それがネットワークとローカルホストのどちらに基づいていても、複数の挿入を1つのクエリに集約すると、常にパフォーマンスが向上します。

拡張挿入の使用を開始する場合は、まず本番環境のデータサンプルといくつかの異なる挿入を使用して環境をテストし、最適な値を見つける必要があります。

1つのクエリの挿入数を増やすときは注意が必要です。そのため、次のことが必要になる場合があります。

  • クライアントにより多くのメモリを割り当てる
  • MySQLサーバーのmax_allowed_pa​​cketパラメーター構成を増やします。

最後に、Perconaによると、パフォーマンスを向上させるために、同時接続、パーティション、および複数のバッファープールを使用できることに言及する価値があります。

ベンチマークは、Centos 7とMySQL 5.7を備えたベアサーバーで実行されます。主なハードウェア構成は、Xeon E3 @ 3.8 GHzプロセッサー、32 GB RAM、NVMe SSDです。MySQLのベンチマークテーブルは、InnoBDストレージエンジンを使用しています。

ベンチマークのソースコードはgistに保存され、結果グラフはplot.lyに保存されます。

おすすめ

転載: www.cnblogs.com/CQqfjy/p/12724022.html