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
エラーが発生することがあります。
私は以下を試しました:
ALTER TABLE tbl_name DISABLE KEYS
を実行しますautocommit=0
、unique_checks=0
、foreign_key_checks=0
max_allowed_packet=999999999G
および関連するタイムアウト変数を同様の値に設定する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
どうもありがとう
RAMまたは文明化された世界のディスク領域には、何を保持することもできませんmax_allowed_packet = 9999999G
割り当てたい!それをデフォルトに戻すか、せいぜい256M
。
SQLファイル自体は、文字通り、数千行の単一のINSERTステートメントです。
これが最適です。
では、テーブルの合計サイズは約0.5テラバイトですか?ディスクの種類にもよりますが、その量のディスクを書き込むのにかかる時間は数時間です。
Not notスワップスペースを使用します。それはMySQLを遅くするだけです。たくさん。ただし、実際の設定ではスワップ領域が使用されていないようです。 buffer_poolの21Gは、RAM使用量を32Gの物理サイズよりも十分に低く保つ必要があります。ただし、100%に急上昇したとおっしゃっていますか?何かが足りないと思います。スワッピングがあると、MySQLの速度が低下します。ダウンしているので、スワップを避けるためにbuffer_pool_sizeを少し下げてください。
autocommit=0
InnoDBでは効率的ではありません-COMMIT
がない場合、データが挿入されてからロールバックされます。 COMMIT
がある場合、ロールバックの準備をするために多くの作業を行う必要があります。 ON
に設定します。
「キー」を300回無効にしてから再度有効にしますか?これは、インデックスが300回再構築されることを意味します。 300を通過するにつれて、ファイルの実行速度はどんどん遅くなりましたか?
私の経験から私は言うでしょう:
max_allowed_packet=10G
(INSERT
でメモリを使用できるようにするため)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
を使用すると高速になります。