AWS RDS MySQL замедляется со временем

AWS RDS MySQL замедляется со временем

Я прочитал много постов на эту тему, но ни в одном из них не говорится о базе данных AWS RDS MySQL. Три дня назад я запустил скрипт Python в экземпляре AWS EC2, который записывает строки в мою базу данных AWS RDS MySQL. Мне нужно записать 35 миллионов строк, поэтому я знаю, что это займет некоторое время. Периодически я проверяю производительность базы данных, и три дня спустя (сегодня) я понимаю, что база данных замедляется. Когда она запустилась, первые 100 000 строк были записаны всего за 7 минут (это пример строк, с которыми я работаю)

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

За три дня в базу данных было записано 5 385 662 строк, но теперь запись 100 000 строк занимает почти 3 часа. Что происходит?

Экземпляр EC2, который я запускаю, — это t2.small. Здесь вы можете проверить спецификации, если вам это нужно:СПЕЦИФИКАЦИИ EC2 . База данных RDS, которую я использую, — db.t2.small. Проверьте спецификации здесь:СПЕЦИФИКАЦИИ RDS

Я приложу здесь несколько диаграмм производительности базы данных и экземпляра EC2: Дб ЦП/Память БД/Запись базы данных IOPS/Пропускная способность записи базы данных/ Сеть EC2 в (байтах)/EC2 Сетевой выход (байты)

Было бы здорово, если бы вы мне помогли. Большое спасибо.

EDIT 1: Как вставлять строки? Как я уже говорил, у меня есть скрипт python, работающий на экземпляре EC2, этот скрипт читает текстовые файлы, производит некоторые вычисления с этими значениями, а затем записывает каждую «новую» строку в базу данных. Вот небольшой фрагмент моего кода. Как читать текстовые файлы?

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) используютКредит ЦПсистема. Когда экземпляр простаивает, он накапливает ЦП-кредиты, которые затем может использовать для ускорения работы в течение коротких периодов времени -Всплеск производительности. Как только вы исчерпаете кредиты, он замедлится доБазовая производительность.

Один из вариантов — включитьT2/T3 безлимитныйнастройка в конфигурации RDS, которая позволит экземпляру работать на полной скорости столько, сколько необходимо, но вам придется заплатить за необходимые дополнительные кредиты.

Другой вариант — изменить тип экземпляра на db.m5 или какой-либо другой тип, отличный от T2/T3, который поддерживает стабильную производительность.

Вот более подробное описаниеобъяснение кредитов ЦПи как они начисляются и расходуются:О разъяснении условий труда t2 и t3?

Надеюсь, это поможет :)

решение2

  • Однорядные INSERTsв 10 раз медленнее 100-рядных INSERTsили 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;

Затем выполните вставки, но пакетируйте их так, чтобы один оператор вставлял (например) несколько десятков строк. Как 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;

Вы можете настроить это для своей ситуации, например, если количество строк огромно, то, возможно, вы захотите вставить полмиллиона, а затем зафиксировать. Это предполагает, что ваша база данных не «живая» (т. е. пользователи не читают/не пишут в нее активно), пока вы делаете вставки, потому что вы отключаете проверки, на которые вы в противном случае могли бы полагаться при вводе данных.

Связанный контент