AWS RDS MySQL 時間の経過とともに速度が低下する

AWS RDS MySQL 時間の経過とともに速度が低下する

このトピックに関する投稿をたくさん読んできましたが、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 行はINSERTs100 行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 万行を挿入してからコミットするとよいでしょう。挿入中はデータベースが「ライブ」ではない (つまり、ユーザーが積極的に読み取り/書き込みを行っていない) ことが前提となります。これは、ユーザーがデータを入力するときに頼りにするチェックを無効にするためです。

関連情報