作爲構建數據倉庫的一部分,我必須查詢大約75M行的源數據庫表。與從CSV文件導出和導入相比,Python MySQLdb SScursor速度較慢。可以加速嗎?
我想對75M行做什麼是一些處理,然後將結果添加到另一個數據庫。現在,這是相當多的數據,我主要有兩種方法取得了成功:
1)使用MySQL的「SELECT ... INTO」功能將查詢導出到CSV文件,並使用文件輸入2)使用MySQLdb的SScursor(默認遊標將查詢放入內存中,殺死python腳本)連接到MySQL數據庫並以大約10k行的塊形式獲取結果(其中是我發現最快的塊大小)。
第一種方法是「手動」執行的SQL查詢(大約需要6分鐘),然後是一個讀取csv文件並處理它的python腳本。我使用fileinput來讀取文件的原因是fileinput不會從頭開始將整個文件加載到內存中,並且對於較大的文件運行良好。只需遍歷文件(讀取文件中的每一行並調用傳遞)需要大約80秒,即1M行/秒。
第二種方法是執行相同查詢的python腳本(也需要大約6分鐘,或稍微長一些),然後只要在SScursor中留下任何剩餘的行,就可以獲取行的塊。在這裏,只要讀取這些行(一個接一個地讀取數據塊而不做其他任何事)需要大約15分鐘,即大約85k行/秒。
上面的兩個數字(行/秒)可能並沒有真正的可比性,但是在我的應用程序中對兩種方法進行基準測試時,第一個需要大約20分鐘(其中大約五分鐘是MySQL轉儲到CSV文件中),第二個大約需要35分鐘(其中大約五分鐘是正在執行的查詢)。這意味着從CSV文件轉儲和讀取數據的速度是直接使用SScursor的兩倍。
如果不限制我的系統的可移植性,這將不成問題:「SELECT ... INTO」語句要求MySQL具有寫入權限,並且我懷疑這不像使用遊標那樣安全。另一方面,15分鐘(隨着源數據庫的增長而增長)並不是我在每次構建時都可以節省的東西。
所以,我錯過了什麼?是否有任何已知的原因讓SScursor比從CSV文件轉儲/讀取要慢得多,例如SScursor不是用於C優化的文件輸入?關於如何解決這個問題的任何想法?任何要測試的東西?我相信SScursor可以像第一種方法一樣快,但在閱讀完所有關於此事的信息後,我很難過。現在
,到代碼:
不,我想查詢任何問題(這是一樣快,我可以要求並採取類似的時間在這兩種方法),但在這裏它是着想完整性:
SELECT LT.SomeID, LT.weekID, W.monday, GREATEST(LT.attr1, LT.attr2)
FROM LargeTable LT JOIN Week W ON LT.weekID = W.ID
ORDER BY LT.someID ASC, LT.weekID ASC;
在第一方法的主要代碼是這樣
import fileinput
INPUT_PATH = 'path/to/csv/dump/dump.csv'
event_list = []
ID = -1
for line in fileinput.input([INPUT_PATH]):
split_line = line.split(';')
if split_line[0] == ID:
event_list.append(split_line[1:])
else:
process_function(ID,event_list)
event_list = [ split_line[1:] ]
ID = split_line[0]
process_function(ID,event_list)
在第二方法的主要代碼是:
import MySQLdb
...opening connection, defining SScursor called ssc...
CHUNK_SIZE = 100000
query_stmt = """SELECT LT.SomeID, LT.weekID, W.monday,
GREATEST(LT.attr1, LT.attr2)
FROM LargeTable LT JOIN Week W ON LT.weekID = W.ID
ORDER BY LT.someID ASC, LT.weekID ASC"""
ssc.execute(query_stmt)
event_list = []
ID = -1
data_chunk = ssc.fetchmany(CHUNK_SIZE)
while data_chunk:
for row in data_chunk:
if row[0] == ID:
event_list.append([ row[1], row[2], row[3] ])
else:
process_function(ID,event_list)
event_list = [[ row[1], row[2], row[3] ]]
ID = row[0]
data_chunk = ssc.fetchmany(CHUNK_SIZE)
process_function(ID,event_list)
最後,我在Ubuntu 13.04上使用MySQL服務器5.5.31。我使用Python 2.7.4和MySQLdb 1.2.3。感謝你和我在一起這麼久!
既然您沒有代表回答您自己的問題,我已將您的問題的部分似乎更像解決方案移到社區維基答案中。如果您有更多的改進來共享和/或接受它,如果它或多或少是完整的,您可以編輯這個wiki答案。 – Air