この質問は、コメントの提案に基づいて Stack Overflow から再投稿されました。重複をお詫びします。
質問1:データベーステーブルのサイズが大きくなると、どのようにMySQLを調整してLOAD DATA INFILE呼び出しの速度を上げることができますか?
質問2:コンピューターのクラスターを使用してさまざまなcsvファイルを読み込み、パフォーマンスを向上させるか、それを強制終了しますか? (これは、ロードデータと一括挿入を使用した明日のベンチマークタスクです)
画像検索のために特徴検出器とクラスタリングパラメータのさまざまな組み合わせを試しています。その結果、大規模なデータベースをタイムリーに構築できる必要があります。
マシンには256ギガのRAMがあり、データベースを分散して作成時間を改善する方法がある場合、同じ量のRAMを使用できる別の2つのマシンがありますか?
テーブルスキーマは次のようになります
_+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| match_index | int(10) unsigned | NO | PRI | NULL | |
| cluster_index | int(10) unsigned | NO | PRI | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| tfidf | float | NO | | 0 | |
+---------------+------------------+------+-----+---------+----------------+
_
で作成
_CREATE TABLE test
(
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL AUTO_INCREMENT,
tfidf FLOAT NOT NULL DEFAULT 0,
UNIQUE KEY (id),
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
_
最初のステップは、一括挿入とバイナリファイルから空のテーブルへの読み込みを比較することでした。
_It took: 0:09:12.394571 to do 4,000 inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file
_
バイナリcsvファイルからデータをロードする際のパフォーマンスの違いを考慮して、最初に、以下の呼び出しを使用して100K、1M、20M、200M行を含むバイナリファイルをロードしました。
_LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;
_
2時間後に200M行のバイナリファイル(〜3GBのcsvファイル)のロードを強制終了しました。
そこで、スクリプトを実行してテーブルを作成し、バイナリファイルからさまざまな数の行を挿入してからテーブルをドロップしました。下のグラフを参照してください。
バイナリファイルから100万行を挿入するのに約7秒かかりました。次に、特定のデータベースサイズでボトルネックが発生するかどうかを確認するために、一度に1M行ずつ挿入するベンチマークを行うことにしました。データベースが約59M行に達すると、平均挿入時間は約5,000 /秒に減少しました
グローバルなkey_buffer_size = 4294967296を設定すると、小さいバイナリファイルを挿入する場合の速度がわずかに向上しました。下のグラフは、行数が異なる場合の速度を示しています
ただし、100万行を挿入した場合、パフォーマンスは向上しませんでした。
行:1,000,000時間:0:04:13.761428挿入/秒:3,940
空のデータベースとの比較
行:1,000,000時間:0:00:6.339295挿入/秒:315,492
次のシーケンスを使用してデータをロードすることと、データをロードするコマンドを使用すること
_SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
_
したがって、これは生成されるデータベースサイズの点で非常に有望に見えますが、他の設定はデータ読み込みファイル内呼び出しのパフォーマンスに影響を与えないようです。
次に、別のマシンから複数のファイルをロードしようとしましたが、ファイルのサイズが大きいために他のマシンがタイムアウトになるため、load data infileコマンドはテーブルをロックします
ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction
_rows: 10,000,000 seconds rows: 0:01:36.545094 inserts/sec: 103578.541236
rows: 20,000,000 seconds rows: 0:03:14.230782 inserts/sec: 102970.29026
rows: 30,000,000 seconds rows: 0:05:07.792266 inserts/sec: 97468.3359978
rows: 40,000,000 seconds rows: 0:06:53.465898 inserts/sec: 96743.1659866
rows: 50,000,000 seconds rows: 0:08:48.721011 inserts/sec: 94567.8324859
rows: 60,000,000 seconds rows: 0:10:32.888930 inserts/sec: 94803.3646283
_
でテーブルを構築する
_CREATE TABLE test (
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL ,
tfidf FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
_
sQLを使って
_LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"
_
スクリプトでインデックスを事前計算することで、データベースのサイズが大きくなるにつれて、パフォーマンスへの影響がなくなったようです。
インメモリテーブルをディスクベースのテーブルに移動するコストを考慮せずに、約3倍高速。
_rows: 0 seconds rows: 0:00:26.661321 inserts/sec: 375075.18851
rows: 10000000 time: 0:00:32.765095 inserts/sec: 305202.83857
rows: 20000000 time: 0:00:38.937946 inserts/sec: 256818.888187
rows: 30000000 time: 0:00:35.170084 inserts/sec: 284332.559456
rows: 40000000 time: 0:00:33.371274 inserts/sec: 299658.922222
rows: 50000000 time: 0:00:39.396904 inserts/sec: 253827.051994
rows: 60000000 time: 0:00:37.719409 inserts/sec: 265115.500617
rows: 70000000 time: 0:00:32.993904 inserts/sec: 303086.291334
rows: 80000000 time: 0:00:33.818471 inserts/sec: 295696.396209
rows: 90000000 time: 0:00:33.534934 inserts/sec: 298196.501594
_
データをメモリベースのテーブルにロードしてからディスクベースのテーブルにコピーする チャンク単位 クエリで107,356,741行をコピーするのに10分59.71秒のオーバーヘッドがありました
_insert into test Select * from test2;
_
100M行をロードするのに約15分かかります。これは、ディスクベースのテーブルに直接挿入するのとほぼ同じです。
良い質問-よく説明されています。
mySQLをチューニングしてLOAD DATA INFILE呼び出しの速度を上げるにはどうすればよいですか?
キーバッファーの設定は既に高くなっていますが、それで十分ですか?これは64ビットインストールであり(そうでない場合、最初に行う必要があるのはアップグレードです)、MSNTで実行されていないと想定しています。いくつかのテストを実行した後、mysqltuner.plの出力を確認してください。
キャッシュを最も効果的に使用するために、入力データのバッチ処理/事前ソートに利点がある場合があります( 'sort'コマンドの最新バージョンには、大規模なデータセットをソートするための多くの機能があります)。また、MySQLの外部でID番号を生成する場合は、より効率的です。
コンピュータのクラスタを使用してさまざまなcsvファイルをロードする
(再度)出力セットを単一のテーブルとして動作させたいとすると、得られる唯一の利点は、IDのソートと生成の作業を分散することです-データベースを追加する必要はありません。 OTOHがデータベースクラスターを使用している場合、競合の問題が発生します(パフォーマンスの問題以外には発生しないはずです)。
データを分割し、結果のデータセットを個別に処理できる場合は、はい、パフォーマンス上の利点が得られますが、これによって各ノードを調整する必要がなくなるわけではありません。
Sort_buffer_sizeに4 GB以上あることを確認してください。
さらに、パフォーマンスを制限する要因は、すべてディスクI/Oにあります。これに対処する方法はたくさんありますが、最適なパフォーマンスを得るために、SSD上のストライプ化されたデータセットのミラーセットを検討する必要があります。
load data...
は挿入よりも高速なので、それを使用してください。本当に気の利いたい場合は、マルチスレッドプログラムを作成して、単一のファイルを名前付きパイプのコレクションにフィードし、挿入インスタンスを管理できます。
要約すると、ワークロードをMySQLに調整するほど、MySQLをこれに合わせて調整することはありません。