2017-07-28 104 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读取它,它将直接通过索引读取。所以它会改善你的表现。