【问题标题】:How to aggregate related object counts in a view effectively?如何有效地聚合视图中的相关对象计数?
【发布时间】:2011-08-18 11:45:22
【问题描述】:

想象一下这个场景:

我的数据库中有三个表:ProductsUsersLikes,后者表示 Product 和一个用户。现在我有一个查询,它将 ProductsLikes 表连接起来,计算一个 Product 获得了多少 Likes。

事实上,我比实际用户更需要有关计数的信息,并且我想将上面的查询用作视图中更大查询的一部分。是否可以优化查询或视图,以便 MySQL 以某种方式缓存上述计数查询的结果?

【问题讨论】:

    标签: mysql sql query-optimization


    【解决方案1】:

    我不知道用 mysql 做这件事的方法(但我主要使用 postgres,所以它可能是可能的,我只是不知道)。我建议两个选项:

    • 如果您需要尽可能保持最新的缓存,请将likes_count 列添加到您的Products 表,在Likes 表上创建AFTER INSERTAFTER DELETE 触发器(假设您从不更新该表),当新行插入Likes 表时增加产品的类似计数,并在删除一行时减少它。然后,添加一个不时执行 UPDATE Products SET likes_count=(SELECT COUNT(1) FROM Likes WHERE product_id = Products.id) 的 cronjob,以确保这些值确实是最新的 - 使用触发器维护计数永远不会 100% 准确。
    • 另一个选项是创建一个视图为CREATE VIEW Products_Likes_View AS SELECT product_id, COUNT(*) AS likes_count FROM Likes GROUP BY product_id;,并创建一个缓存表,类似于CREATE TABLE Products_Likes_Cache (product_id INTEGER PRIMARY KEY, likes_count INTEGER NOT NULL);。然后,添加一个执行 BEGIN; TRUNCATE Products_Likes_Cache; INSERT INTO Products_Likes_Cache SELECT * FROM Products_Likes_View; COMMIT; 的 cronjob,它将缓存表与视图中的最新信息同步。比,如果您需要准确的结果,您可以直接从视图中获取数据。否则,使用缓存表。

    如果你选择第一个选项,触发器应该看起来像这样(我的 MySQL 技能有点生疏,我可能不了解确切的语法):

    CREATE TRIGGER product_increase_likes AFTER INSERT ON Likes
        FOR EACH ROW BEGIN
            UPDATE Products SET likes_count=likes_count+1 WHERE id=NEW.product_id
        END;
    
    CREATE TRIGGER product_decrease_likes AFTER DELETE ON Likes
        FOR EACH ROW BEGIN
            UPDATE Products SET likes_count=likes_count-1 WHERE id=OLD.product_id
        END;
    

    【讨论】:

    • 感谢您非常详细的回答和实际示例!
    【解决方案2】:

    您不需要加入来计算产品的点赞数。

    SELECT product, count(*) 
    FROM likes
    GROUP BY product;
    

    如果你使用 WHERE 子句,应该会很快。

    【讨论】:

      猜你喜欢
      • 2019-01-12
      • 1970-01-01
      • 2022-12-16
      • 2012-10-14
      • 1970-01-01
      • 2012-05-13
      • 2019-11-25
      • 2017-07-31
      • 1970-01-01
      相关资源
      最近更新 更多