このトピックに関する投稿をたくさん読んできましたが、AWS RDS MySQL データベースについて言及しているものはありません。3 日前から、AWS EC2 インスタンスで、AWS RDS MySQL データベースに行を書き込む Python スクリプトを実行しています。3,500 万行を書き込む必要があるため、時間がかかることはわかっています。定期的にデータベースのパフォーマンスをチェックしていますが、3 日後 (今日)、データベースの速度が低下していることに気付きました。開始時には、最初の 10 万行がわずか 7 分で書き込まれました (これは、私が作業している行の例です)
0000002178-14-000056 AccountsPayableCurrent us-gaap/2014 20131231 0 USD 266099000.0000
3 日後、データベースに 5,385,662 行が書き込まれましたが、現在は 100,000 行を書き込むのに 3 時間近くかかります。何が起こっているのでしょうか。
私が実行している EC2 インスタンスは t2.small です。必要に応じて、ここで仕様を確認できます。EC2 仕様 私が実行している RDS データベースは db.t2.small です。仕様はここで確認してください。RDS 仕様
ここに、データベースと EC2 インスタンスのパフォーマンスに関するいくつかのグラフを添付します。 デシベルCPU/Dbメモリ/DB 書き込み IOPS/DB 書き込みスループット/ EC2 ネットワーク (バイト)/EC2 ネットワーク出力 (バイト)
ご協力いただければ幸いです。よろしくお願いします。
編集 1: 行を挿入するにはどうすればよいですか? 前にも述べたように、EC2 インスタンスで実行されている Python スクリプトがあります。このスクリプトはテキスト ファイルを読み取り、これらの値を使用して計算を行い、すべての「新しい」行をデータベースに書き込みます。以下は私のコードの一部です。 テキストファイルをどのように読みますか?
for i in path_list:
notify("Uploading: " + i)
num_path = "path/" + i + "/file.txt"
sub_path = "path/" + i + "/file.txt"
try:
sub_dict = {}
with open(sub_path) as sub_file:
for line in sub_file:
line = line.strip().split("\t")
sub_dict[line[0]] = line[1] # Save cik for every accession number
sub_dict[line[1] + "-report"] = line[25] # Save report type for every CIK
sub_dict[line[1] + "-frecuency"] = line[28] # Save frecuency for every CIK
with open(num_path) as num_file:
for line in num_file:
num_row = line.strip().split("\t")
# Reminder: sometimes in the very old reports, cik and accession number does not match. For this reason I have to write
# the following statement. To save the real cik.
try:
cik = sub_dict[num_row[0]]
except:
cik = num_row[0][0:10]
try: # If there is no value, pass
value = num_row[7]
values_dict = {
'cik': cik,
'accession': num_row[0][10::].replace("-", ""),
'tag': num_row[1],
'value': value,
'valueid': num_row[6],
'date': num_row[4]
}
sql = ("INSERT INTO table name (id, tag, value_num, value_id, endtime, cik, report, period) "
"VALUES ('{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}')".format(
values_dict['cik'] + values_dict['accession'] + values_dict['date'] + values_dict['value'].split(".")[0] + "-" + values_dict['tag'],
values_dict['tag'],
float(values_dict['value']),
values_dict['valueid'],
values_dict['date'],
int(values_dict['cik']),
sub_dict[values_dict['cik'] + "-report"],
sub_dict[values_dict['cik'] + "-frecuency"]
))
cursor.execute(sql)
connection.commit()
except:
ステートメントをキャッチする必要がないことはわかっていますtry
が、これはスクリプトの一部にすぎません。重要なのは、各行をどのように挿入するかだと思います。値を使用して計算する必要がない場合は、Load Data Infile
テキスト ファイルをデータベースに書き込むために使用します。行を挿入するたびに行うのは、おそらく良い考えではないことに気付きましたcommit
。10,000 行程度後にコミットするようにします。
答え1
T2およびT3インスタンス(db.t2 db.t3インスタンスを含む)はCPUクレジットシステム。インスタンスがアイドル状態のときにCPUクレジットを蓄積し、それを使って短時間で高速に実行できるようにします。バーストパフォーマンスクレジットを使い切ると、ベースラインパフォーマンス。
1つの選択肢は、T2/T3 無制限RDS 構成で設定すると、インスタンスを必要な時間だけフルスピードで実行できますが、必要な追加クレジットに対して料金を支払う必要があります。
もう 1 つのオプションは、インスタンス タイプを db.m5 または一貫したパフォーマンスをサポートするその他の非 T2/T3 タイプに変更することです。
より詳しい内容はこちらCPUクレジットの説明どのように蓄積され、使用されるか:t2 と t3 の動作条件を明確にすると?
お役に立てれば幸いです :)
答え2
1 行は
INSERTs
100 行INSERTs
またはの 10 倍遅くなりますLOAD DATA
。UUID は、特にテーブルが大きくなると遅くなります。
UNIQUE
インデックスをチェックする必要がある前にを終えるiNSERT
。非一意な処理
INDEXes
はバックグラウンドで実行できますが、それでも負荷がかかります。
SHOW CREATE TABLE
と、 に使用した方法を提供してくださいINSERTing
。 他にもヒントがあるかもしれません。
答え3
トランザクションをコミットするたびに、インデックスを更新する必要があります。インデックスの更新の複雑さはテーブル内の行数に関係するため、行数が増えると、インデックスの更新は次第に遅くなります。
InnoDB テーブルを使用している場合は、次の操作を実行できます。
SET FOREIGN_KEY_CHECKS = 0;
SET UNIQUE_CHECKS = 0;
SET AUTOCOMMIT = 0;
ALTER TABLE table_name DISABLE KEYS;
次に挿入を実行しますが、1つのステートメントで数十行を挿入するようにバッチ処理しますINSERT INTO table_name VALUES ((<row1 data>), (<row2 data>), ...)
。挿入が完了したら、
ALTER TABLE table_name ENABLE KEYS;
SET UNIQUE_CHECKS = 1;
SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
これを自分の状況に合わせて調整できます。たとえば、行数が非常に多い場合は、50 万行を挿入してからコミットするとよいでしょう。挿入中はデータベースが「ライブ」ではない (つまり、ユーザーが積極的に読み取り/書き込みを行っていない) ことが前提となります。これは、ユーザーがデータを入力するときに頼りにするチェックを無効にするためです。