mysqldumpからのデータの読み込み速度が遅い


21

約30のテーブルを持つ適度なサイズのMySQLデータベースがあり、そのうちのいくつかは1,000万レコード、およそ1億レコードです。mysqldump(別のファイルに)すべてのテーブルのは、かなり速いです多分20分かかります。約15GBのデータを生成します。最大のダンプファイルは2GBの範囲です。

別のボックス、6コア、8GBマシンのMySQLにデータをロードすると、永遠に時間がかかります。簡単に12時間以上。

私はファイルをロードするためにmysqlクライアントを実行しています、すなわち

mysql database < footable.sql

mysqldumpから直接ファイルを直接

mysqldump database foo > footable.sql

明らかに私は何か間違ったことをしている。妥当な時間内に終了できるように、どこから始めますか?

ダンプでもロードでもスイッチを使用していません。


ダンプのロード中にバイナリロギングを無効にすることもできます
セドリックPEINTRE

回答:


22

ダンプを生成して復元する場合に役立つ可能性があるこれらの点を考慮してください。

  1. Extended insertsダンプで使用します。
  2. ダンプ--tabあなたが使用できるようにフォーマットmysqlimportよりも速くなります、mysql < dumpfile
  3. 各テーブルに1つずつ、複数のスレッドでインポートします。
  4. 可能であれば、別のデータベースエンジンを使用してください。innodbのような重いトランザクションエンジンへのインポートは非​​常に遅くなります。MyISAMのような非トランザクションエンジンへの挿入は、はるかに高速です。
  5. 外部キーチェックをオフにし、自動コミットをオンにします。
  6. innodbにインポートする場合にできる最も効果的な方法はinnodb_flush_log_at_trx_commit = 2、インポートの実行中に一時的にmy.cnf を配置することです。ACIDが必要な場合は、1に戻すことができます

試してみる..


あなたのヒントはinnodb_flush_log_at_trx_commit = 2私の一日を救った。600 MBのダンプを(1つの大きなトランザクションとして)インポートするには6時間かかりましたが、この一時的な設定では30分で完了しました!
ダニエルマーシャル

1
「enter」を押してから4日後にダンプから80gigデータベースをロードしようとする前に知っておくべきこと... :)
Dmitri DB

7

アブドゥルの答えに加えて、--disable-keysすべてのデータがテーブルにロードされるまでキーをオフにするオプションの重要性を強調したいと思います。このオプションは--opt、デフォルトで有効になっているトグルの一部として有効になっていますが、指摘することが重要だと考えました。

挿入中にキーをスキップしない場合、挿入された各行はインデックスを再構築します。非常に遅いプロセス。


--disable-keysはmysqldumpの一部ですか?またはリロード?
パットファレル

ダンプファイルに追加されます
デレクダウニー

--optデフォルトでオンになっています
-jberryman

1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
イーサンアレン

7

私は最近これをたくさん扱ってきました。インポートを並行して行うことにより、インポートのパフォーマンスを確実に向上させることができます。スローダウンの大部分はI / Oベースですが、テーブルにダンプしてから一度に4ずつインポートすることで、40%の改善が得られます。

次のようなxargsでこれを行うことができます。

ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"

ファイルをmysqlにプッシュする前にgzip圧縮しても、主にI / Oが低下するため、速度が低下することはありません。私のテーブルは最大約10:1に圧縮されているため、多くのディスクスペースを節約できます。

4つのコアマシンでは、4つのプロセスを使用するのが最適であることがわかりました。ただし、3を使用するよりもわずかに優れています。

注意すべきその他の事項。あなたは4kのセクターのドライブを持っている場合は、確認してくださいあなたが持っているkey_cache_block_size=4096myisam_block_size=4K

MyISAMテーブルを使用している場合は、myisam_repair_threads = 2以上を設定します。これにより、追加のコアを使用してインデックスを再構築できます。

まったく交換していないことを確認してください。もしそうなら、のサイズを小さくしてくださいinnodb_buffer_pool_size

私はこれらのオプションによってinnnodbの速度もいくらか向上したと思います。

innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0

(最後の3つは広範囲にテストしませんでした-インターネット上で提案として見つけたと思います。)innodb_flush_log_at_commit=0mysqlがクラッシュしたり、電源が切れたりして破損する可能性があることに注意してください。


グレッグ、このサイトへようこそ。回答ありがとうございます。*_block_sizeおよびについての提案のソースまたは理由を提供してくださいmyisam_repair_threads。また、必ず私たちは:)「のインターネットからの提案」に基づいて調整する変数へのアドバイスを提供する必要がありません
デレク・ダウニー

5

主にMyISAMテーブルがある場合は、一括挿入バッファーを増やす必要があります。bulk_insert_buffer_sizeの設定に関するMySQLドキュメントの内容は次のとおりです。

MyISAMは、特別なツリーのようなキャッシュを使用して、空でないデータを追加するときに、INSERT ... SELECT、INSERT ... VALUES(...)、(...)、...、およびLOAD DATA INFILEの一括挿入を高速化しますテーブル。この変数は、スレッドごとのキャッシュツリーのサイズをバイト単位で制限します。0に設定すると、この最適化が無効になります。デフォルト値は8MBです。

あなたがする必要がある2つのことがあります

1)/etc/my.cnfに追加します

[mysqld]
bulk_insert_buffer_size=512M

2)グローバル値を設定します

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

bulk_insert_buffer_sizeをグローバルに設定する権限がない場合は、これを実行します

service mysql restart

もちろん、これはInnoDB用ではありません。

別の角度から、テーブルがInnoDBかMyISAMかに関係なく、インデックスがテーブルよりも大きい場合、インデックスが多すぎる可能性があります。私は通常、MyISAM mysqldumpのリロードには、mysqldumpの作成にかかった時間の3倍の時間がかかると推測しています。また、InnoDB mysqldumpのリロードには、mysqldumpの作成にかかった時間の4倍の時間がかかると推測しています。

mysqldumpのリロードで4:1の比率を超えている場合、間違いなく2つの問題のいずれかがあります。

  • インデックスが多すぎる
  • 大きい列のためにインデックスが大きすぎます

これにより、ストレージエンジンごとにデータのサイズを測定できます。

SELECT IFNULL(B.engine,'Total') "Storage Engine",
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(
FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(
FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM
(SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,
SUM(data_length+index_length) TSize FROM
information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND
engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,
(SELECT 3 pw) A ORDER BY TSize;

インデックスがデータと同じくらい大きいか、さらに大きいかを確認します

また、次のようにバイナリロギングを無効にすることも検討できます。

echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql

スクリプトをリロードする前に


あなたが私の一日を何回救ったかわかりませんが、それは確かにたくさんありました
Dmitri DB

2

ファイルシステムを完全にバイパスし、mysqldumpの出力を直接MySQLプロセスにパイプするだけで、顕著なパフォーマンスの改善が見られるはずです。最終的には、使用しているディスクドライブの種類によって異なりますが、この理由だけで、データベースサイズに関係なく、ダンプファイルを使用することはほとんどありません。

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy

1

私の経験によると、ハードドライブがボトルネックです。回転ディスクを忘れてください。SSDの方が優れていますが、データベース全体を短時間保持するのに十分な場合は、これをRAMで実行するのが最善です。大体:

  1. mysqldを停止します
  2. / var / lib / mysqlの既存のコンテンツを移動します
  3. 空の/ var / lib / mysql dirを作成します
  4. mount -t tmpfs -o size = 32g tmpfs / var / lib / mysql(サイズを調整)
  5. 空のdbを作成します(mysql_install_dbなど、以前の内容を復元します)
  6. mysqldを起動します
  7. インポート
  8. mysqldを停止します
  9. / var / lib / mysqlをmysql2にコピーします
  10. mysqlをマウント解除します。rmdir mysql
  11. mysql2をmysqlに移動する
  12. mysqldを起動して、幸せに

私にとっては、〜10G(/ var / lib / mysql消費〜20G)のダンプは、約35分(mydumper / myloader)、45分(mysqldump --tab / mysqlimport)、50分(mysqldump / mysql)でインポートできます、2x6コア3.2GHz Xeonで。

単一のマシンに十分なRAMがないが、高速ネットワークを備えた複数のコンピューターが隣り合っている場合、それらのRAMがnbd(ネットワークブロックデバイス)に参加できるかどうかを確認するのは興味深いでしょう。または、innodb_file_per_tableを使用すると、おそらく各テーブルに対して上記のプロセスを繰り返すことができます。


好奇心から、mysql datadirをRAMに保存して、2 GBのデータベースのSSD(興味のある方はSSDSC2BB48)と比較してみました。結果は同一で、両方とも207〜209秒かかりました。はるかに遅い私の場合は、あなたも代わりにSSDのRAMディスクを使用して、開始/停止MySQLを持っているとディレクトリをコピーしているという事実を考慮して
ショッカー

約3〜4分かかった場合、このトピックの内容よりもかなり小さいデータベースがあると思います。このトピックで言及したものと同様の大規模なデータベースでの経験について聞くのは興味深いでしょう。
エグモント
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.