四百万行数据,GROUP BY 后统计,然后 DESC 排序后,还要分页
id 主键
user_id 用户 ID
date 创建日期
SELECT
user_id,
count(*) AS count
FROM
log
GROUP BY
date, user_id
ORDER BY
date DESC, user_id DESC
LIMIT 0, 10
以上 SQL 语句可以走索引,但是这时候如果要 count 字段进行排序,explain 就走全表了,执行了 1 分半,有其他办法优化吗?
SELECT
user_id,
count(*) AS count
FROM
log
GROUP BY
date, user_id
ORDER BY
count DESC, date DESC, user_id DESC
LIMIT 0, 10
1
setsunakute 2019-10-11 16:19:12 +08:00
select `user`, count from (
SELECT `date`, user_id, count(*) AS count FROM log GROUP BY date, user_id ) as a order by count DESC, `date` DESC, user_id DESC limit 0, 10; 这样试试? |
2
ShutTheFu2kUP OP @setsunakute 貌似还是一个结果,子查询不走索引,我启动强制索引,虽然 explain 的 key 有索引,但是还是 row 还是全表的行数
|
3
ShutTheFu2kUP OP 是我自己傻了...子查询还是走索引的,只是因为子查询里没有 LIMIT,所以行数还是全表的行数...
|
4
reus 2019-10-11 16:55:23 +08:00
不走全表,是没可能算出结果的,你怎么优化都不能违背基本逻辑。
可以给 date 加范围条件,如果业务允许的话。 |
5
ShutTheFu2kUP OP @reus 是的..在不重构表的情况下我也只能想到这个方法了..
|
6
saulshao 2019-10-11 17:48:00 +08:00
这种我之前的办法都是把 count 结果直接写到表里....然后查询这个表...
|
7
zhengwhizz 2019-10-11 20:37:55 +08:00 via Android 1
首先要确认你的业务场景,从语句来看只是要知道用户每天的操作次数,这其实属于数据统计了,你的日志表为原始数据表,每次请求都去拿原始表肯定很慢,所以要建立一个统计表(userid, count, date ),然后在每次用户有操作时 count 加 1 (实时性要求高的情况),或者定时脚本把前一天的统计了放进去。这种设计还可以满足时间段的统计,只需要 sum 下即可。
|
8
Caballarii 2019-10-11 20:40:53 +08:00
redis
|
9
Leigg 2019-10-11 20:46:51 +08:00 via Android
兄 die,你是要全表排序啊,怎么避免扫全表。需求,表设计,库选择,总有一个是有问题的。
非要在现有的基础上解决这个问题,楼上的建议是不错的。 |
10
ShutTheFu2kUP OP @zhengwhizz 嗯,谢谢大佬,我的思路也是如果重构就用字段+1 的方式。定时统计也是一种解决办法,之前没有想到,感谢指导
|