【问题标题】:How to aggregate related object counts in a view effectively?如何有效地聚合视图中的相关对象计数?
【发布时间】:2011-08-18 11:45:22
【问题描述】:
想象一下这个场景:
我的数据库中有三个表:Products、Users 和 Likes,后者表示 Product 和一个用户。现在我有一个查询,它将 Products 与 Likes 表连接起来,计算一个 Product 获得了多少 Likes。
事实上,我比实际用户更需要有关计数的信息,并且我想将上面的查询用作视图中更大查询的一部分。是否可以优化查询或视图,以便 MySQL 以某种方式缓存上述计数查询的结果?
【问题讨论】:
标签:
mysql
sql
query-optimization
【解决方案1】:
我不知道用 mysql 做这件事的方法(但我主要使用 postgres,所以它可能是可能的,我只是不知道)。我建议两个选项:
- 如果您需要尽可能保持最新的缓存,请将
likes_count 列添加到您的Products 表,在Likes 表上创建AFTER INSERT 和AFTER 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 子句,应该会很快。