【问题标题】:OR query performance and strategies with PostgresqlOR 使用 Postgresql 的查询性能和策略
【发布时间】:2010-02-23 15:55:41
【问题描述】:

在我的应用程序中,我有一个应用程序事件表,用于生成用户特定的应用程序事件源。因为它是使用 OR 查询生成的,所以我担心这个频繁使用的查询的性能,并且想知道我是否处理错了。

在应用程序中,用户可以关注其他用户和组。当执行一个动作(例如,创建一个新帖子)时,将创建一个feed_item 记录,其中actor_id 设置为用户的ID,subject_id 设置为执行该操作的组ID,并且actor_typesubject_type 设置为模型的类名。由于用户可以同时关注组和用户,因此我需要生成一个同时检查 actor_id 和 subject_id 的查询,并且它需要选择不同的记录以避免重复。因为它是一个 OR 查询,所以我不能使用普通索引。而且由于每次执行操作时都会创建一条记录,因此我希望该表很快就会有很多记录。

这是当前查询(following 表将用户连接到 feeders,也就是用户和组)

SELECT DISTINCT feed_items.* FROM "feed_items" 
 INNER JOIN "followings" 
 ON (
 (followings.feeder_id = feed_items.subject_id 
 AND followings.feeder_type = feed_items.subject_type)
 OR
 (followings.feeder_id = feed_items.actor_id 
 AND followings.feeder_type = feed_items.actor_type)
 )
 WHERE (followings.follower_id = 42) ORDER BY feed_items.created_at DESC LIMIT 30 OFFSET 0

所以我的问题:

  • 由于这是一个频繁使用的查询,这里是否存在性能问题?

  • 有什么明显的方法可以简化或优化我所缺少的吗?

【问题讨论】:

    标签: sql database performance postgresql


    【解决方案1】:

    你所拥有的被称为独家弧,你会明白为什么这是一个坏主意。解决此类问题的最佳方法是使提要项类型动态化:

    • Feed 项目:id、类型(A 或 S 代表 Actor 或 Subject)、子类型(替换 actor_type 和 subject_type)

    然后你的查询就变成了

    SELECT DISTINCT fi.*
    FROM feed_items fi
    JOIN followings f ON f.feeder_id = fi.id AND f.feeder_type = fi.type AND f.feeder_subtype = fi.subtype
    

    或类似的。

    这可能不能完全或准确地代表您需要做的事情,但原则是合理的:您需要通过更改数据模型来消除 OR 条件的原因,以使其适合编写高性能查询它。

    【讨论】:

    • 似乎使用这种方法我需要为每个动作创建两个提要项,一个用于演员和主题,然后过滤掉重复项,因为当演员和主题时会返回重复项两者都被跟踪。除非我完全不在基地,否则我可能还需要一个action_id 并做类似SELECT feed_items.* FROM feed_items WHERE feed_items.action_id IN (SELECT DISTINCT fi.action_id FROM feed_items fi JOIN followings f ON f.feeder_id = fi.id AND f.feeder_type = fi.type AND f.feeder_subtype = fi.subtype) 的事情,对吗?它比 OR 更好吗?
    【解决方案2】:

    解释分析和时间查询,看看是否有问题。

    所以您可以尝试将查询表示为联合

    SELECT x.* FROM
    (
    SELECT feed_items.* FROM feed_items
    INNER JOIN followings 
    ON  followings.feeder_id = feed_items.subject_id 
        AND followings.feeder_type = feed_items.subject_type
    WHERE (followings.follower_id = 42)
    UNION
    SELECT feed_items.* FROM feed_items
    INNER JOIN followings
     followings.feeder_id = feed_items.actor_id 
     AND followings.feeder_type = feed_items.actor_type)
    WHERE (followings.follower_id = 42)
    ) AS x
    ORDER BY x.created_at DESC 
    LIMIT 30
    

    但再次解释分析和基准测试。

    【讨论】:

      【解决方案3】:

      要确定是否存在性能问题,请对其进行测量。 PostgreSQL 可以为你explain 它。

      我认为查询不需要简化,如果您发现性能问题,那么您可能需要修改索引。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-04
        • 2023-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多