我在名为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
函数中执行计算,例如十多个销售数量年期间。我不能轻松访问装有RAM的机器,除非我开始使用EC2进入城镇,我担心这会花费很多而且非常麻烦。
建议将不胜感激。
答案 0 :(得分:1)
我也遇到了类似的问题,下面的代码帮助我有效地阅读了数据库(约4千万行)。
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.它将直接通过索引读取。所以它会提高你的表现。
答案 1 :(得分:0)
由于操作中的瓶颈是SQL WHERE查询,因此解决方案是索引WHERE语句运行的列(即zipcode列)。
在MySQL中,对此的命令是:
ALTER TABLE `db_name`.`table`
ADD INDEX `zipcode_index` USING BTREE (`zipcode` ASC);
进行此更改后,循环执行速度提高了8倍。
我发现this article非常有用,因为它鼓励使用EXPLAIN
进行概要分析,并在key
和possible_key
值为NULL