我讀過很多關於這個主題的文章,但沒有一篇討論 AWS RDS MySQL 資料庫。自三天前以來,我在 AWS EC2 執行個體中執行 python 腳本,該腳本在我的 AWS RDS MySQL 資料庫中寫入資料列。我必須寫入 3500 萬行,所以我知道這需要一些時間。我定期檢查資料庫的效能,三天後(今天)我意識到資料庫正在變慢。當它開始時,前 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 執行個體效能的圖表: 資料庫CPU/資料庫記憶體/資料庫寫入 IOPS/資料庫寫入吞吐量/ 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 積分,然後可以使用這些積分在短時間內運行得更快 -爆發性能。一旦你耗盡了積分,它就會減慢到基線性能。
一種選擇是啟用T2/T3 無限在您的 RDS 配置中進行設置,這將使實例在需要時全速運行,但您將支付所需的額外積分。
另一個選項是將實例類型變更為 db.m5 或支援一致性能的其他非 T2/T3 類型。
這裡有一個更深入的CPU積分的解釋以及如何累積和花費:關於明確t2和t3的工作條件?
希望有幫助:)
答案2
單行的速度
INSERTs
比 100 行慢 10INSERTs
倍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;
您可以根據自己的情況進行調整,例如,如果行數很大,那麼您可能想要插入 50 萬行,然後提交。這假設您在執行插入時資料庫不是「活動的」(即使用者主動讀取/寫入資料庫),因為您停用了輸入資料時可能依賴的檢查。