2017-07-28 253 views
2

我有一個名爲sale_transactions的數據庫表中有2200萬行房產銷售數據。我正在執行一項工作,在該工作中,我從該表中讀取信息,執行一些計算,並使用結果爲新表創建條目。過程是這樣的:優化大熊貓計算

for index, row in zipcodes.iterrows(): # ~100k zipcodes 
    sql_string = """SELECT * from sale_transactions WHERE zipcode = '{ZIPCODE}' """ 
    sql_query = sql_string.format(ZIPCODE=row['zipcode'])   
    df = pd.read_sql(sql_query, _engine) 
    area_stat = create_area_stats(df) # function does calculations 
    area_stat.save() # saves a Django model 

目前這個循環的每個迭代發生在我的MacBook Pro(16GB RAM),這意味着該代碼將需要數週時間才能完成約20秒。昂貴的部分是read_sql系列。

我該如何優化?我無法將整個sale_transactions表讀入內存,大約5 GB,因此每次使用sql查詢都可以使用WHERE子句捕獲相關行。

大多數關於優化大熊貓的答案都是關於分塊閱讀的討論,但在這種情況下,我需要對所有數據進行WHERE組合,因爲我在create_area_stats函數中執行計算,如十年期間的銷售數量。我沒有辦法輕鬆訪問一臺裝有內存的機器,除非我開始去EC2這個城市,我擔心這樣會很貴,而且很麻煩。

建議將不勝感激。

+1

你可能要檢查,如果你能在RDBMS優化,例如剖析在郵編上添加索引。使用參數化查詢可能會產生更好的性能,而不是在每次迭代時都提供不同的sql字符串。 – bgse

回答

0

由於操作中的瓶頸是SQL WHERE查詢,因此解決方案是索引WHERE語句操作的列(即zipcode列)。

在MySQL,這樣做的命令是:

ALTER TABLE `db_name`.`table` 
ADD INDEX `zipcode_index` USING BTREE (`zipcode` ASC); 

進行此更改之後,循環執行速度提高了8倍。

我發現this article有用,因爲它鼓勵使用EXPLAIN查詢和觀察列索引的機會時keypossible_key值分別爲NULL

1

我也遇到了類似的問題,下面的代碼幫助我有效地讀取數據庫(約4000萬行)。

offsetID = 0 
totalrow = 0 



while (True): 

    df_Batch=pd.read_sql_query('set work_mem="1024MB"; SELECT * FROM '+tableName+' WHERE row_number > '+ str(offsetID) +' ORDER BY row_number LIMIT 100000' ,con=engine) 
    offsetID = offsetID + len(df_Batch) 

    #your operation 

    totalrow = totalrow + len(df_Batch) 

您必須在表格中創建一個名爲row_number的索引。所以這段代碼將讀取你的表(100 000行)索引。例如當你想讀取200 000到210 000行時,你不需要從0到210 000讀取它,它將直接通過索引讀取。所以它會改善你的表現。