2017-07-28 31 views
0

私は、pythonとsqlalchemyを使用してデータベーステーブルを作成する関数を持っています。この機能は今のところかなり遅く17分ほどかかっています。私は主な問題は、私は新しいテーブルを構築するために2つの大きなデータセットをループしていると思います。私は以下のコードにレコード数を含めました。pythonとsqlalchemy関数を高速化

これをスピードアップするにはどうすればよいですか?入れ子にされたforループを1つの大きなsqlalchemyクエリに変換する必要がありますか?私はpycharmでこの機能をプロファイリングしましたが、結果を完全に理解しているかどうかはわかりません。

def populate(self): 
    """Core function to populate positions.""" 

    # get raw annotations with tag Org 
    # returns 11,659 records 
    organizations = model.session.query(model.Annotation) \ 
     .filter(model.Annotation.tag == 'Org')\ 
     .filter(model.Annotation.organization_id.isnot(None)).all() 

    # get raw annotations with tags Support or Oppose 
    # returns 2,947 records 
    annotations = model.session.query(model.Annotation) \ 
     .filter((model.Annotation.tag == 'Support') | (model.Annotation.tag == 'Oppose')).all() 

    for org in organizations: 
     for anno in annotations: 

      # Org overlaps with Support or Oppose tag 
      # start and end columns are integers 
      if org.start >= anno.start and org.end <= anno.end: 
       position = model.Position() 
       # set to de-duplicated organization 
       position.organization_id = org.organization_id 
       position.disposition = anno.tag 
       # look up bill_id from document_bill table 
       document = model.session.query(model.document_bill)\ 
        .filter_by(document_id=anno.document_id).first() 
       position.bill_id = document.bill_id 
       position.document_id = anno.document_id 
       model.session.add(position) 
       logging.info('org: {}, disposition: {}, bill: {}'.format(
        position.organization_id, position.disposition, position.bill_id) 
       ) 
       continue 
     logging.info('committing to database') 
     model.session.commit() 
+0

すでに動作しているコードの改善については、[codereview.se]よりもStack Overflowより適しています。 – jwodder

+2

'bill_id'を取得するために少なくとも11,659 * 2947 = 34,359,073クエリを実行しています。どのように*遅くない*ことができますか? 'model.session.commit()'もすべての 'organization'と' annotations'を期限切れにします。つまり、内部ループ 'anno'が' org'の最初の反復のたびに一度リフレッシュされ、11,658 * 2947 = 34,356,126クエリ合計68,715,199件のクエリであり、その大半は無駄な作業です。ループ外の単一のクエリで 'document_bill'をクエリし、コミット時に' annotations'を期限切れにしないようにすることができます。最後に、インサートを一括して実行できるかどうかを確認します。 – univerio

+0

ありがとう! model.session.commit()を外側のループに移動してみましょう。つまり、最後に1回実行されます。私はループの外でdocument_billクエリーをどのように動かすことができるのか理解していません。ループ内で提供されているanno.document_idの現在の値に依存するためです。 – Casey

答えて

0

私のベット、確率の高い順で:

  • 自動コミットがONになっているので、あなたはディスクを待っています。
  • ループ内のクエリ "document = model.session.query(model.document_bill)...."が遅い(EXPLAIN ANALYZEを使用)。
  • 時間のほとんどは、実際に(プロファイルはずです)、内側のループで端末に印刷ログを費やしている
  • model.session.add(位置)
  • (およびこれ(それが何をするか全く分からない)遅いです1つは本当に最初にすべきです)INSERT INTO SELECTのようなSQLクエリは数十ミリ秒でこれを行うことができますか?もしそうなら、なぜアプリケーションのループを作るのですか?...