AWS RDSMySQLは時間の経過とともに遅くなります

Aug 24 2020

このトピックに関する多くの投稿を読みましたが、AWS RDSMySQLデータベースについてはどれも話していません。3日前から、AWS RDSMySQLデータベースに行を書き込むAWSEC2インスタンスでPythonスクリプトを実行しています。私は3500万行を書かなければならないので、これには時間がかかることを知っています。定期的にデータベースのパフォーマンスをチェックしていますが、3日後(今日)にデータベースの速度が低下していることに気付きました。それが始まったとき、最初の100,000行はわずか7分で書き込まれました(これは私が作業している行の例です)

0000002178-14-000056    AccountsPayableCurrent  us-gaap/2014        20131231    0   USD 266099000.0000

3日後、5,385,662行がデータベースに書き込まれましたが、現在、100,000行を書き込むのに約3時間かかります。何が起こっている?

私が実行しているEC2インスタンスはt2.smallです。必要に応じて、ここで仕様を確認できます:EC2SPECS。私が実行しているRDSデータベースはdb.t2.smallです。ここで仕様を確認してください:RDS SPECS

ここに、データベースとEC2インスタンスのパフォーマンスに関するいくつかのチャートを添付します:Db 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行程度でコミットしようと思います。

回答

11 MLu Aug 24 2020 at 06:03

T2およびT3インスタンス(db.t2 db.t3インスタンスを含む)はCPUクレジットシステムを使用します。インスタンスがアイドル状態の場合、CPUクレジットが蓄積され、これを使用して短時間で高速に実行できます-パフォーマンスのバースト。クレジットを使い果たすと、ベースラインのパフォーマンスが低下します。

1つのオプションは、RDS構成でT2 / T3 Unlimited設定を有効にすることです。これにより、インスタンスは必要な限りフルスピードで実行されますが、必要な追加のクレジットは有料になります。

もう1つのオプションは、インスタンスタイプをdb.m5または一貫したパフォーマンスをサポートするその他の非T2 / T3タイプに変更することです。

CPUクレジットと、それらがどのように発生し、使用されるかについて、より詳細に説明します。t2およびt3の動作条件を明確にすることについて。

お役に立てば幸いです:)

9 RickJames Aug 24 2020 at 07:09
  • 単一行INSERTsは、100行INSERTsまたはの10倍の速度LOAD DATAです。

  • 特にテーブルが大きくなると、UUIDは遅くなります。

  • UNIQUEを終了するに、インデックスをチェックする必要がありますiNSERT

  • 非一意INDEXesはバックグラウンドで実行できますが、それでもある程度の負荷がかかります。

SHOW CREATE TABLE使用した方法とを提供してくださいINSERTing。もっとヒントがあるかもしれません。

7 tater Aug 23 2020 at 23:07

トランザクションをコミットするたびに、インデックスを更新する必要があります。インデックスの更新の複雑さはテーブルの行数に関連しているため、行数が増えると、インデックスの更新は徐々に遅くなります。

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万を挿入してからコミットすることができます。これは、挿入を行っている間、データベースが「ライブ」ではない(つまり、ユーザーがデータベースに対してアクティブに読み取り/書き込みを行っている)ことを前提としています。これは、データを入力するときに信頼できるチェックを無効にしているためです。