web-dev-qa-db-ja.com

とんでもない量のメモリを使用して1〜2GBのSQLファイルをインポートするMySQL

Dockerを介してUbuntu18.04マシンで実行されているMySQLサーバーがあります。マシンには32GBのRAMがあります。

サーバー上のデータベースにインポートする必要のある1〜2GBのSQLファイルが約300個あります。

データベース自体は完全に空であり、合計で1つのテーブルしかありません。

一部のファイルをインポートしようとすると、メモリ使用量が32 GB(100%)に急増し、100 GBのスワップメモリ​​を割り当てた後、60 GBになるのがわかります( 60 GB + 32 GB = 92 GB !!!)

MySQLが92GBのRAMを使用して1GBのSQLファイルを空のデータベースの単一のテーブルにインポートしようとしていることを念頭に置いて、それはおそらく何をしているのでしょうか?ファイルのインポートが完了すると、メモリが割り当てられなくなるため、メモリリークが発生します。

MySQLは、ホストがデータを格納するために直接ファイルアクセスできるDockerボリュームを使用していることをおそらく言及する必要があります。

この問題を解決するためにさまざまな構成を試しましたが、さらにMySQL server has gone awayエラーが発生することがあります。

私は以下を試しました:

  • テーブルをInnoDBからMyISAMに変更し、ALTER TABLE tbl_name DISABLE KEYSを実行します
  • 設定autocommit=0unique_checks=0foreign_key_checks=0
  • max_allowed_packet=999999999Gおよび関連するタイムアウト変数を同様の値に設定する
  • mysqltuner.pl を使用して、いくつかの最適なInnoDB構成オプションを生成します(以下を参照)。

SQLファイル自体は、文字通り、数千行の単一のINSERTステートメントです。

私に何ができる? INSERTステートメントを複数の異なるINSERTにチャンク化することを検討しましたが、SQLファイルを生成するプログラムのマルチプロセッシングフローのため、これにはいくつかの広範なコードリファクタリングが必要になります。

my.cnf

[mysqld]
max_allowed_packet = 9999999G
wait_timeout = 99999999999
key_buffer_size=10M
innodb_buffer_pool_size=21G
innodb_log_file_size=2G
innodb_buffer_pool_instances=21
innodb_file_per_table
net_read_timeout=999999999999
net_write_timeout=999999999999

pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
secure-file-priv= NULL
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

# Custom config should go here
!includedir /etc/mysql/conf.d/

この問題は、innodb_*変数を追加していじった後も一貫して持続しました。

グローバル変数を表示

https://Pastebin.com/raw/pXK4MgFb

どうもありがとう

2
Billy

RAMまたは文明化された世界のディスク領域には、何を保持することもできませんmax_allowed_packet = 9999999G割り当てたい!それをデフォルトに戻すか、せいぜい256M

SQLファイル自体は、文字通り、数千行の単一のINSERTステートメントです。

これが最適です。

では、テーブルの合計サイズは約0.5テラバイトですか?ディスクの種類にもよりますが、その量のディスクを書き込むのにかかる時間は数時間です。

Not notスワップスペースを使用します。それはMySQLを遅くするだけです。たくさん。ただし、実際の設定ではスワップ領域が使用されていないようです。 buffer_poolの21Gは、RAM使用量を32Gの物理サイズよりも十分に低く保つ必要があります。ただし、100%に急上昇したとおっしゃっていますか?何かが足りないと思います。スワッピングがあると、MySQLの速度が低下します。ダウンしているので、スワップを避けるためにbuffer_pool_sizeを少し下げてください。

autocommit=0InnoDBでは効率的ではありません-COMMITがない場合、データが挿入されてからロールバックされます。 COMMITがある場合、ロールバックの準備をするために多くの作業を行う必要があります。 ONに設定します。

「キー」を300回無効にしてから再度有効にしますか?これは、インデックスが300回再構築されることを意味します。 300を通過するにつれて、ファイルの実行速度はどんどん遅くなりましたか?

1
Rick James

私の経験から私は言うでしょう:

  • インポートセット中:
    • max_allowed_packet=10GINSERTでメモリを使用できるようにするため)
    • innodb_buffer_pool_size=10G(またはそれ以下)を使用してサーバーのメモリを解放します。後でサーバーをクエリに使用しているときにこれを増やすことができますが、挿入の場合はほとんど役に立ちません。
    • innodb_flush_log_at_trx_commit = 0 I/Oパフォーマンスを向上させるため(本番環境で使用する場合は、必ず削除するか、1または2に設定してください!)

また、1つのトランザクションには大きすぎるINSERTステートメントに問題があります。基本的に、トランザクションがREDOログに対して大きすぎる場合、失敗します。確実にAUTOCOMMIT=1を設定し、ダンプファイルからSTART TRANSACTION行を削除します。これで問題が解決しない場合は、ログファイルのサイズを増やします。 https://dba.stackexchange.com/a/ 1265/12685


さらに、これらのSQLファイルをプログラムで生成していることに気付きました。特に上記の設定では、これらの挿入を1つずつデータベースサーバーに送信する方が効率的であり、INSERT DELAYEDを使用すると高速になります。

0
Stefan Seidel