2017-07-28 59 views
0

我有一个函数,使用python和sqlalchemy填充数据库表。功能运行速度相当缓慢,大约需要17分钟。我认为主要问题是我正在循环两组大数据来构建新表。我在下面的代码中包含了记录数。加速Python w/sqlalchemy函数

如何加快速度?我应该尝试将嵌套的for循环转换为一个大的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

有关改进已经工作的代码的问题比Stack Overflow更适合[codereview.se]。 – jwodder

+2

您正在运行至少11,659 * 2947 = 34,359,073查询来获取'bill_id';这怎么可能*不会很慢? 'model.session.commit()'也会使所有'组织'和'注释'到期,这意味着在你的内部循环中'anno'在'org'的第一次迭代之后每刷新一次,添加另外11,658 * 2947 = 34,356,126个查询,总计68,715,199个查询,其中大部分是浪费的工作。您可以从循环之外的单个查询中查询“document_bill”,然后确保在提交时不会过期注释。最后,看看你是否可以批量插入。 – univerio

+0

谢谢!我会尝试将model.session.commit()移动到外部循环,因此它在最后运行一次。我不明白如何将document_bill查询移到循环外部,因为它取决于循环中提供的anno.document_id的当前值。 – Casey

回答

0

我的赌注,在递减概率高的顺序:

  • 自动提交的,所以你要等待磁盘。
  • 循环“document = model.session.query(model.document_bill)....”中的查询很慢(使用EXPLAIN ANALYZE)。
  • 大部分的时间花在实际打印日志到该终端在该内环(你就应该剖析)
  • model.session.add(位置)慢(不知道做什么)
  • (这其中一个应该是真正的第一个)像INSERT INTO SELECT这样的SQL查询可以在几十毫秒内完成这个操作吗?如果是的话,为什么要在应用程序中循环?...