我有一个查询正在更新过去24小时内的观看次数和喜欢,但速度非常慢。对于大约3000个帖子,完成需要15秒以上,这是一个很大的问题,因为在此期间无法执行其他查询。
$update_query = mysqli_query($database, "UPDATE post SET
likes_last_day = (SELECT COUNT(post_like_id) FROM post_like WHERE post.post_id = post_like.post_id AND post_like.date > ('$current_date' - INTERVAL 1 DAY)),
views_last_day = (SELECT COUNT(post_view_id) FROM post_view WHERE post.post_id = post_view.post_id AND post_view.date > ('$current_date' - INTERVAL 1 DAY))");
有没有办法优化此查询以更快地执行?
答案 0 :(得分:0)
这是您的查询:
UPDATE post p
SET likes_last_day = (SELECT COUNT(*) FROM post_like l WHERE p.post_id = l.post_id AND l.date > ('$current_date' - INTERVAL 1 DAY)),
views_last_day = (SELECT COUNT(*) FROM post_view v WHERE p.post_id = v.post_id AND v.date > ('$current_date' - INTERVAL 1 DAY));
您正在使用子查询更新3000行。这需要一些时间。要加快查询速度,您可以使用索引:post_like(post_id, date)
和post_view(post_id, date)
。
您还可以在加入结果之前重写查询以进行聚合。但是,我怀疑使用正确的索引相关子查询实际上可能会更快。
答案 1 :(得分:0)
如果在添加索引后性能仍然存在问题,您可能会考虑在存储过程中执行此操作,因此db将重用执行计划,而不是为每个即席查询构建它。
答案 2 :(得分:0)
为了最小化锁定在post表上的时间,我们可以将结果预先聚合到临时表中,然后从中执行更新。
举个例子:
DROP TEMPORARY TABLE IF EXISTS `__post_last_day_counts__`
;
CREATE TEMPORARY TABLE `__post_last_day_counts__`
( post_id BIGINT NOT NULL COMMENT 'pk'
, likes_last_day BIGINT NOT NULL
, views_last_day BIGINT NOT NULL
, PRIMARY KEY (post_id)
) ENGINE=InnoDB
;
INSERT INTO `__post_last_day_counts__`
( post_id
, likes_last_day
, views_last_day
)
SELECT p.post_id
, IFNULL(lc.likes_last_day,0) AS likes_last_day
, IFNULL(vc.views_last_day,0) AS views_last_day
FROM post p
LEFT
JOIN ( SELECT pl.post_id
, COUNT(pl.post_id) AS likes_last_day
FROM post_like pl
WHERE pl.date > ('$current_date' - INTERVAL 1 DAY)
) lc
ON lc.post_id = p.post_id
LEFT
JOIN ( SELECT pv.post_id
, COUNT(pv.post_id) AS views_last_day
FROM post_view pv
WHERE pv.date > ('$current_date' - INTERVAL 1 DAY)
) vc
ON vc.post_id = p.post_id
;
使用临时表中的计数,我们可以更新帖子表...
UPDATE post t
JOIN `__post_last_day_counts__` s
ON s.post_id = t.id
SET t.likes_last_day = s.likes_last_day
, t.views_last_day = s.views_last_day
;
清理......
DROP TEMPORARY TABLE IF EXISTS `__post_last_day_counts__`
;
总的来说,这可能是较慢,但它可以最小化UPDATE语句持有锁定的时间。
注意:临时表中post_id
列的数据类型应与post_id
表中post
的数据类型匹配。我只是猜了一下。
我们假设post_id
是帖子表的主键(或唯一键)。
确保有合适的索引:
... on post_view (post_id, date)
... on post_like (post_id, date)
使用EXPLAIN查看执行计划,正在执行哪些操作以及正在使用哪些索引。 (我们希望在Extra列中看到"在组和#34中使用索引。)