mysql分页的问题
用过mysql的人肯定知道,mysql提供了原生的分页功能-----LIMIT关键字。LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。TIPS:初始记录行的偏移量是 0(而不是 1)。
但是我再实际的项目过程中使用LIMIT子句时,在分页数目很大的情况下(几万页),后面的翻页的速度明显慢于前面,特别好奇这个现象的原因,于是explain了一下,才发现mysql LIMIT 10000, 20的意思扫描满足条件的10020行,扔掉前面的10000行,返回最后的20行。如下所示:
EXPLAIN SELECT * FROM exp_platform ORDER BY id DESC LIMIT 10000,5
***************** 1. row **************
id: 1
select_type: SIMPLE
table: message
type: index
possible_keys: NULL
key: PRIMARY
key_len: 4
ref: NULL
rows: 10020
Extra:
1 row in set (0.00 sec)
这相当于越往后面翻页越相当于全表扫描,这样在一个高并发的应用下,性能肯定是hold不住的。但是LIMIT n这样的语句性能是没有问题的,因为只扫描n行。于是就想找解决办法,如下:
Solution1:使用LIMIT n
"clue法":大概的思路就是在where语句根据id或者别的字段做一些限制。但是这个思路只能提供“上一页”、“下一页”这样的跳转,因为你需要拿到上一页或者下一页的id然后再根据where语句筛选,再使用LIMIT N来做。这样的话,不管翻多少页,每次查询只扫描20行。
SELECT * FROM exp_platform WHERE id >= 9500 LIMIT 5
Solution2:使用子查询
SELECT * FROM exp_platform WHERE id >= (SELECT id FROM exp_platform ORDER BY id LIMIT 10000, 1) LIMIT 20
子查询是在索引上完成的,而普通查询是在数据文件上完成的,通常来说,索引文件要比数据文件小很多,所以操作起来更有效
Solution3:使用JOIN分页方式,这个没有尝试过,有机会可以试试。
实际可以利用类似策略模式的方式去处理分页,比如判断如果是一百页以内,就使用最基本的分页方式,大于一百页,则使用子查询的分页方式。