2017-07-28 14 views
2

sales_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(16ギガバイトRAM)に約20秒かかります。高価な部分はread_sql行です。

これをどのように最適化できますか?私はsale_transactionsテーブル全体をメモリに読み込むことはできません。それは約5GBです。そのたびにsqlクエリを使用してWHERE句で関連する行を取得します。

パンダの最適化に関するほとんどの回答は、チャンクで読むことについて話していますが、このケースでは、10年以上の売上のように、create_area_stats関数で計算を行っているため、すべてのデータを組み合わせてWHEREを実行する必要があります。私はEC2で町に行くことを開始しない限り、RAMの負荷のあるマシンに簡単にアクセスすることはできません。私は高価でかなりの労力がかかると心配しています。

提案をいただければ幸いです。

+1

いたとき、列のインデックスのための機会を観察することが奨励ので、私はthis articleが有用であることが判明郵便番号にインデックスを追加します。反復ごとに異なるSQL文字列を入力するのではなく、パラメタ化クエリを使用するとパフォーマンスが向上する場合もあります。 – bgse

答えて

0

操作のボトルネックはSQL WHEREクエリであったため、解決策はWHERE文が動作していた列(つまり、郵便番号列)にインデックスを付けることでした。

はMySQLでは、このためのコマンドは:

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

この変更を行った後、ループの実行速度が8倍に増加しました。

それはEXPLAINを使用してクエリをプロファイリングし、keypossible_key値は、例えば、あなたがRDBMSに最適化することができますかどうかを確認することをお勧めします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の値を読み取る必要はありません。インデックスで直接読み取られます。だからあなたのパフォーマンスを向上させます。

関連する問題