【问题标题】:Efficient queries for relationships in SQLAlchemySQLAlchemy 中关系的高效查询
【发布时间】:2014-01-25 15:15:38
【问题描述】:

一点背景知识:我正在创建一个在组织内部使用的 Web 应用程序(使用 Flask)。该网络应用程序将有一个非常简单的留言板,允许用户发布和评论帖子。

我这样做有几个原因——主要是为了获得使用 Flask 的经验并更好地理解 sqlalchemy。

这是删除了一些不重要信息的数据库架构:

class User(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    # information about user
    posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')
    comments = db.relationship('Comment', backref = 'author', lazy = 'dynamic')

class Post(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    # information about posts (title, body, timestamp, etc.)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    comments = db.relationship('Comment', backref = 'thread', lazy = 'dynamic')

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    # information about comment (body, timestamp, etc)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))   # author
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))   # thread

当我呈现消息视图时,我希望能够显示一个线程表,其中包含每条消息的以下信息:

  • 标题
  • 作者
  • # 回复
  • 上次修改时间

现在,我获取消息的查询如下所示:

messages = Post.query.filter_by(post_type = TYPE_MESSAGE).order_by('timestamp desc')

通过该查询,我可以轻松获得每篇文章的标题和作者。但是,它目前按创建消息的日期排序(我知道这是错误的,我也知道原因),我无法轻易获得回复的数量。

如果我正在循环浏览消息以在应用程序中呈现它们,我可以访问 message.comments 属性并使用它来查找长度并获取最新评论的时间戳,但是我是否正确假设要获取该数据需要另一个数据库查询(访问message.comments)?

既然如此,我可以通过一个查询获得所有消息的列表(很好),但如果我有 n 消息,则需要 n 额外的数据库查询来填充消息视图我想要的信息,这远远没有效率。

这让我想到了我的主要问题:是否可以像在常规 SQL 查询中那样在 SQLAlchemy 中使用聚合运算符来获取 messages 的原始查询中的 COUNT(comments)MAX(timestamp)?或者,还有其他我尚未探索的解决方案吗?理想情况下,我希望能够在一个查询中完成所有这些操作。我查看了 SQLAlchemy 文档,找不到类似的东西。谢谢!

【问题讨论】:

  • 我相信大多数论坛软件通过将这两个值存储在Post 级别来解决这个问题。它消除了对频繁显示的信息进行连接的需要,尤其是在您检索多个帖子时。
  • 这是有道理的。从您所说的来看,似乎我必须向Post 添加一个名为回复的属性,并在每次添加评论时增加它。 Post 然后必须有类似add_comment(c) 函数的东西(不一定是好的设计——删除评论时会发生什么?)或者是否有另一种方法可以通过 SQLAlchemy 来做到这一点,只要将评论添加到数据库中引用了某个Post?
  • 我个人会在数据库中使用触发器。如果你想把东西保存在 ORM 中,Flask-SQLAlchemy has support for a couple of signals.
  • 感谢您的链接!我不知道为什么我没有考虑触发器。你有使用 SQLAlchemy 的经​​验吗?为每个评论添加两个触发器(更新回复和最后修改)会使 cmets 的插入速度稍慢一些,但它应该比执行所有这些查询来填充消息视图更快。另外,我使用的是 0.7.9 版。旧版本有类似的支持吗?
  • 如果你使用数据库触发器,SQLAlchemy 不需要做任何事情(除非你想执行CREATE TRIGGER 语句)。如果您想使用 SQLAlchemy 中的信号,这些信号已经存在了一段时间。他们肯定在 0.7.9 中。

标签: python sql database optimization sqlalchemy


【解决方案1】:

对于计数,你可以试试这个(一个例子):

session.query(Comment).join(Post).filter_by(id=5).count()

sess.query(Comment).join(Post).filter(Post.id==5).count()

而且,是的,您可以使用聚合:

sess.query(func.max(Comment.id)).join(Post).filter_by(id=5).all()

sess.query(func.max(Comment.id)).join(Post).filter(Post.id==5).all()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 2016-10-19
    • 2020-09-02
    • 2013-10-11
    • 1970-01-01
    • 2021-01-06
    相关资源
    最近更新 更多