Sql 优化查询-使用字段或其他表

Sql 优化查询-使用字段或其他表,sql,hibernate,database-design,jpa,Sql,Hibernate,Database Design,Jpa,我有一个查询需要很长时间,我想优化它。我在寻找最有效的方法 我正在使用Postgresql DB开发Hibernate/JPA,但任何解决方案都应该是通用的JPA解决方案 术语 用户:系统中的用户 朋友:用户的朋友。一个用户将有N个朋友 会话:使用系统的会话。可以打开或关闭 上下文:会话的上下文。在任何给定的时间内,用户可能在每个上下文中有一个打开的会话,并且可能在每个上下文中有许多过去关闭的会话 查询 我需要实现一个查询,在给定用户名的情况下,该查询将提供以下信息: 获取该用户的所有好友

我有一个查询需要很长时间,我想优化它。我在寻找最有效的方法

我正在使用Postgresql DB开发Hibernate/JPA,但任何解决方案都应该是通用的JPA解决方案

术语

  • 用户:系统中的用户
  • 朋友:用户的朋友。一个用户将有N个朋友
  • 会话:使用系统的会话。可以打开或关闭
  • 上下文:会话的上下文。在任何给定的时间内,用户可能在每个上下文中有一个打开的会话,并且可能在每个上下文中有许多过去关闭的会话
查询

我需要实现一个查询,在给定用户名的情况下,该查询将提供以下信息:

  • 获取该用户的所有好友
  • 每一位朋友:
    • 如果朋友有任何打开的会话,则获取所有打开的会话(针对所有上下文)
    • 否则,请从所有上下文中获取好友的最新会话
请注意,友谊存储在不同的数据库中,因此在任何情况下,我都无法将其合并到一个大查询中

示例

用户A有三个朋友:B、C、D。有两个上下文,1和2。朋友们有以下数据:

(以下格式为会话ID-用户,上下文)

  • 1-B,1:公开会议
  • 2-B,2:2月27日开始的非公开会议
  • 3-B,2:2月26日开始的非公开会议
  • 4-C,1:2月27日开始的非公开会议
  • 5-C,1:2月26日开始的非公开会议
  • 6-C,2:2月26日开始的非公开会议
  • 7-C,2:2月25日开始的非公开会议
  • 8-D,1:公开会议
  • 9-D,2:公开会议
查询应该会让我: B:第1次会议(所有公开会议) C:第4次会议(最近一次非公开会议) D:第8、9次会议(所有公开会议)

当前状态

我的查询分为三个步骤:

  • 获取用户的所有好友
  • 每一位朋友:
  • 为好友获取所有开放会话
  • 如果存在任何打开的会话,请返回所有打开的会话
  • 获取好友的最新会话,然后返回该会话
  • 显然,这是一个很大的查询首先,我将执行上面的步骤2,并将其转换为单个查询。我关心的是第二个问题。问题是-如何使其更优化。因此,问题可以重新表述为:

    给定一组N个好友ID,获取所有这些好友的所有打开会话或最新会话

    建议的解决方案

    我们基本上提出了两种解决方案,我们正在考虑更好的方案

    表解决方案表示保留一个新表,该表将在用户、上下文和最新会话之间关联。这一解决方案的含义是:

    • 为“最新会话”创建新实体和表
    • 该表将包含以下列:
      • 使用者
      • 上下文
      • 最新会话ID
    • 该表将由会话实体在持久化后更新,因此任何新持久化的会话都将自动更新该表
    • 新查询将从此表中获取用户所有好友的所有记录,并对其进行处理以创建最终结果
    列解决方案表示在sessions表中保留一个“latest”标志列。这一解决方案的含义是:

    • 为最新字段创建新字段(布尔值)
    • 该列将由会话实体的post persist设置,这样以前的“最新”会话将不再是最新的会话,而新会话将成为最新的会话
    • 新查询将从原始sessions表中获取用户所有好友的所有最新记录(通过将新列合并到语句的条件中),并对其进行处理以创建最终结果

    每种方法都有利弊,我们似乎还没有赢家。显然,我们还没有考虑到其他更好的解决方案。我想看看上面哪一个更好,为什么更好,或者你自己的一个更好的新方法。

    为什么不缓存对象?您不需要点击数据库。

    两种解决方案之间的差异应该是微不足道的。表解决方案可能更干净,具体取决于活动

    然而,一定要注意“你做错了”(根据理论)

    RDBMS应用程序设计原则明确指出,您不应该尝试指定查询的执行方式,而应该指定您需要的数据。数据库将找到解决方案的最佳路径(RDBMS距离数据最近,根据您的体系结构,它可能会节省网络往返、存储往返等等;在这里,可扩展性可能会严重受损,如果您不进行适当的压力测试,您可能不会意识到这一点;此外,RDBMS知道索引和内部统计信息,这些信息决定了扫描或查找是否有效更有效,它知道如何以最佳方式执行连接)

    在实践中,试着提出这样一个问题:为什么不同的数据库用于友谊?(是真的不同的数据库还是同一数据库上的不同模式?)

    此外,如果您真的想按自己的方式去做(禁用RDBMS以寻找最佳执行计划),那么最重要的因素是:

    • 索引(将以数量级影响性能)
    • 使用模式(索引将提高选择的性能,但太多的索引将减慢更新速度)
    • 应用程序/客户端层缓存(可能会影响性能和可伸缩性,数量级)
    编辑: 因此,考虑到“给定一组N个好友ID,获取所有这些好友的所有打开会话或最新会话”
    SELECT *
    FROM Sessions s
    WHERE s.End IS NULL 
          AND s.User IN (:friendsList)
    UNION ALL
    SELECT *
    FROM Sessions s
    WHERE s.User NOT IN (SELECT User 
                         FROM Sessions s2
                         WHERE s2.User IN (:friendsList)
                               AND s2.End IS NULL)
          AND s.User IN (:friendsList)          
          AND s.End IN (SELECT MAX(End) 
                        FROM Sessions s2 
                        WHERE s2.User = s.User)