【问题标题】:How to load at once all objects related to specified in SQLAlchemy?如何一次加载与 SQLAlchemy 中指定的相关的所有对象?
【发布时间】:2013-06-26 14:02:45
【问题描述】:

这是我的数据库的简化项目。

我的模型是由 SQLAlchemy 创建的,看起来像这样

#!/usr/bin/python

class Book(Base):
    id = Column(Integer, primary_key = True)
    title = Column(Unicode(512))
    sentenses = relationship("Sentense", backref = backref("book", uselist = False))
    isbns = relationship("ISBN", secondary = books_isbns, backref = "book")
    authors = relationship("Author", secondary = books_authors, backref = "book")

class Sentense(Base):
    id = Column(Integer, primary_key = True)
    content = Column(Unicode(512))
    words = relationship("Word", secondary = sentenses_words, backref = "sentense")

class Word(Base):
    id = Column(Integer, primary_key = True)
    content = Column(Unicode(32), index = True, unique = True)
    soundex_id = Column(Integer, ForeignKey('Soundex.id'))

class Soundex(Base):
    id = Column(Integer, primary_key = True)
    code = Column(Unicode(5), index = True, unique = True)
    words = relationship("Word", backref = backref("soundex", uselist = False))

问题在于对象加载的时间。使用很棒的profiler 我得到了这个:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   111                                               @staticmethod
   112                                               @profile
   113                                               def getBooksWithSimilarWordsLikeInThisSentence(session, sentense):
   114        16           51      3.2      0.0          s = set()
   115        89       116294   1306.7      0.1          for word in sentense.words:
   116      4200       712414    169.6      0.5              for word in word.soundex.words:
   117     33690     13370590    396.9      8.7                  for sentense in word.sentense:
   118     29563       130437      4.4      0.1                      if sentense.id != sentense.id:
   119     18732     44930792   2398.6     29.3                          s.add(sentense.book)
   120                                           
   121        16          709     44.3      0.0          list_of_other_books = list(s)
   122                                           
   123
   124     18748        25865      1.4      0.0          for book in list_of_other_books:
   125
   126     39016     48461924   1242.1     31.6              for authors in book.authors:
   127     20284       564884     27.8      0.4                  print authors.name
   128                                           
   129     33896     44392639   1309.7     29.0              for isbn in book.isbns:
   130     15164       421289     27.8      0.3                  print isbn.raw
   131                                           
   132     18732       133320      7.1      0.1              books.add(book)
   133                                           
   134        16          926     57.9      0.0          return list(books)

有没有办法一次加载与书籍对象相关的所有内容?我试过使用 session.refresh() 对象,但它没有给出任何结果。

【问题讨论】:

    标签: python sqlalchemy relationship eager-loading


    【解决方案1】:

    您发布的代码仅处理查询结果 - 将句子传递给函数。问题是默认情况下所有关系都是惰性的,因此它们需要更多的 SQL 查询才能工作,这可能会很慢。

    解决方案是预先加载所有需要的关系。这样的事情会让你到达那里:

    # import sqlalchemy as sa
    sentense = Sentense.query.options(sa.joinedload_all(
            "words.soundex.words.sentense.book.authors"
        ), sa.joinedload_all(
            "words.soundex.words.sentense.book.isbns"
        )).filter(<some filters here>).first()
    

    请注意,这可能仍然很慢,我不知道您的数据库和数据的详细信息,但它会导致一次发送一个大型查询。

    还要注意您的代码还有其他问题。关系的“边”似乎是随机的,名字的复数并不一致,让人难以理解。在分析代码中,您在 for 循环期间覆盖传入的语句,因此 sentense.id != sentense.id 将始终评估 False。您还可以用内部 for 循环中的 word 覆盖外部 for 循环中的 word

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-05
      • 2015-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      相关资源
      最近更新 更多