web-dev-qa-db-ja.com

ファイル内ロードを使用したバルクロードの前または後にインデックスを付けますか?

(PKに加えて)インデックスが付けられた1Bを超える行と2つの列を持つデータベースがあります。ファイル内のロード前にテーブルにインデックスを事前定義しておくのが良いですか、それともデータがロードされた後にインデックス付けする方が良いですか?

データサイズとシステムに関する注意事項:

  • システムはLinuxで、8コアと32GBのメモリを備えています(現在、新しいハードウェアに移動しない限り、最大になっています)。
  • DBは1B行で、生データのサイズは150GBデータです。
  • データベースはMyISAMであり、ロードされた後は主に読み取り専用になります。
6
user21689

私は1Bを超えて同様のデータロードでさまざまなソリューションを試しましたが、私が見つけたより良いのはこれです。

mysqlのドキュメントから

テーブルに多くのインデックスがある場合、MyISAMテーブルの追加の作業により、LOAD DATA INFILEをさらに高速に実行することができます。次の手順を使用します。

  1. FLUSH TABLESステートメントまたはmysqladmin flush-tablesコマンドを実行します。

  2. myisamchk --keys-used=0 -rq /path/to/db/tbl_nameを使用して、テーブルのインデックスの使用をすべて削除します。

  3. LOAD DATA INFILEを使用してデータをテーブルに挿入します。これはインデックスを更新しないため、非常に高速です。

  4. myisamchk -rq /path/to/db/tbl_nameを使用してインデックスを再作成します。これにより、ディスクに書き込む前にメモリにインデックスツリーが作成されます。これにより、多くのディスクシークが回避されるため、LOAD DATA INFILE中にインデックスを更新するよりもはるかに高速になります。結果のインデックスツリーも完全にバランスが取れています。

  5. FLUSH TABLESステートメントまたはmysqladmin flush-tablesコマンドを実行します。

LOAD DATA INFILEは、データを挿入するMyISAMテーブルが空の場合、前述の最適化を自動的に実行します。 自動最適化とプロシージャの明示的な使用の主な違いは、myisamchkにインデックス作成用の一時メモリを割り当てて、サーバーがインデックスの再作成に割り当てる場合よりも多くの一時メモリを割り当てることができることです。 LOAD DATA INFILEステートメントを実行します

Myisamchkからより良いパフォーマンスを得るには、次のようないくつかのパラメーターを調整する必要があります。

--key_buffer_size --myisam_sort_buffer_size --read_buffer_size --write_buffer_size

ハードウェアアーキテクチャに応じて

注意

LOCALLOAD DATAと共に使用すると、ファイルのコピーがサーバーの一時ディレクトリに作成されます。これは、tmpdirまたはslave_load_tmpdirの値によって決定されるディレクトリではなく、オペレーティングシステムの一時ディレクトリであり、MySQLサーバーでは構成できません。

だから、あなたはこの種の問題を抱えており、あなたのファイルはcsvです、あなたはあなたの「巨大な」ファイルをチャンクに分割することができます

$ split -l (numbersofrowsinfile / ((filesize/tmpsize) + 1)) /path/to/your/<file>.csv

次に、すべてのチャンクファイルに対してLOAD DATA LOCAL(手順3)を繰り返します。

4
Cristian Porta

CristianはすでにMySQL固有の考慮事項のかなりの数をカバーしているように見えるので、私はこの答えについては一般的なままにしておきます。

一括操作の一般的な推奨事項は、後でインデックスを削除して再構築することです。各インデックスのツリー構造のバランスを維持するための作業量はかなり多く、挿入順序によっては、大幅なインデックスの断片化(つまり、データファイル内のページの場所)と使用されるスペースの量(可能性があります)部分的に使用されているページの割合が高い)。

テーブルにデータがない場合、一般的なアドバイスは次のとおりです。

  1. すべてのインデックスを削除します。一意の制約もインデックスであることに注意してください。ただし、受信データがその点で有効であることが確実でない限り、そのままにしておきます。 PKもインデックスですが、FKがPKを参照している場合、それらを削除することはできません(また、入ってくるデータに重複が含まれていないことがわかっている場合にのみ必要です)。一般的な考えに反して、外部キーはすべてのRDBMSのインデックスを意味するわけではありません(参照 http://www.sqlskills.com/blogs/kimberly/when-did-sql-server-stop-putting-indexes-on-foreign -key-columns /
  2. 一括挿入を行います。
  3. テーブルは主に読み取り専用になるので、主キーを再構築します(多くのDBMSでは、これにより断片化とスペースの無駄が減ります)。
  4. インデックス、およびそれらを削除した場合は一意の制約を、高いフィルファクターで再作成します。クラスタ化インデックスがある場合は、他のインデックスや制約の前にこれを(再)作成してください。

テーブルにすでにデータがある場合、このアドバイスはもちろん慎重に再検討する必要があります。テーブルのコンテンツの70%以上を追加または更新する場合は、インデックスを削除して再作成する価値がある古い「経験則」を覚えていますが、そうでない場合はそうではありませんが、そのルールに適切な根拠があるかどうかはわかりません実験を実行するか、またはそれが1人の専門家によって薄い空気から引き抜かれ、他のすべての人によって繰り返された場合!また、既存のデータドロップインデックスと制約が存在する場合、ユーザーがシステムをアクティブに使用している場合、データベースバックが問題になります。

もちろん、時間が許せば、本番環境にデータをインポートする前にテストを実行できるマシンがあれば、プロセスごとに独自のベンチマークを実行できます。

4
David Spillett