Я прочитал много сообщений по этой теме, но ни в одном из них не говорится о базе данных MySQL AWS RDS. Три дня назад я запускаю скрипт python в экземпляре AWS EC2, который записывает строки в мою базу данных MySQL AWS RDS. Мне нужно написать 35 миллионов строк, поэтому я знаю, что это займет некоторое время. Периодически я проверяю производительность базы данных, и через три дня (сегодня) я понимаю, что база данных замедляется. Когда он запускался, первые 100000 строк были записаны всего за 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: Db CPU / Db Память / Db Запись IOPS / Пропускная способность записи в БД / Сеть EC2 в (байтах) / EC2 Network out (байты)
Было бы здорово, если бы вы могли мне помочь. Большое спасибо.
РЕДАКТИРОВАТЬ 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 строк или около того.
Экземпляры T2 и T3 (включая экземпляры db.t2 db.t3) используют Кредит ЦП система. Когда экземпляр простаивает, он накапливает CPU Credits, которые затем можно использовать для более быстрой работы в течение коротких периодов времени - Взрывная производительность. Как только вы исчерпаете кредиты, он замедлится до Базовая производительность.
Один из вариантов - включить T2 / T3 без ограничений в конфигурации RDS, которая позволит экземпляру работать на полной скорости столько, сколько необходимо, но вы заплатите за необходимые дополнительные кредиты.
Другой вариант - изменить тип экземпляра на db.m5 или другой тип, отличный от T2 / T3, который поддерживает стабильную производительность.
Вот более подробный объяснение кредитов CPU и как они начисляются и расходуются: Об уточнении условий работы t2 и t3?
Надеюсь, это поможет :)
Один ряд INSERTs
в 10 раз медленнее, чем 100-рядный INSERTs
или LOAD DATA
.
UUID работают медленно, особенно когда таблица становится большой.
UNIQUE
индексы необходимо проверить перед заканчивая iNSERT
.
Неуникальный INDEXes
можно делать в фоновом режиме, но они все равно берут на себя некоторую нагрузку.
Пожалуйста предоставьте SHOW CREATE TABLE
и метод, используемый для INSERTing
. Может быть еще подсказок.
Каждый раз, когда вы фиксируете транзакцию, необходимо обновлять индексы. Сложность обновления индекса зависит от количества строк в таблице, поэтому по мере увеличения количества строк обновление индекса становится все медленнее.
Предполагая, что вы используете таблицы 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;
Вы можете настроить это для своей собственной ситуации, например, если количество строк огромное, тогда, возможно, вы захотите вставить полмиллиона, а затем зафиксировать. Это предполагает, что ваша база данных не «живая» (т.е. пользователи, активно читающие / записывающие в нее), пока вы выполняете вставки, потому что вы отключаете проверки, на которые в противном случае вы могли бы полагаться при вводе данных.