Home MySQL分页查询优化
Post
Cancel

MySQL分页查询优化

MySQL一般使用LIMIT实现分页,基本语句为:

1
2
3
SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT ...
-- 分页计算方法
SELECT ... FROM ... WHERE ... ORDER BY ... (#{pageNum} - 1) * #{pageSize}, #{pageSize}

提示:

select from_user, realname, mobile from testtable LIMIT (1-1)*10, 10报错

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near “(1-1)*10,10” at line 2

原因是limit后面是不能做计算,只能直接写limit x, x

在中小数据量的情况下,这样的SQL足够用了,唯一需要注意的问题就是确保使用了索引。举例来说,如果实际SQL类似下面语句,那么在category_id,id两列上建立复合索引比较好:

1
SELECT * FROM articles WHERE category_id = 123 ORDER BY id LIMIT 50, 10;

随着数据量的增加,页数会越来越多,查看后几页的SQL就可能类似下面这种:

1
SELECT * FROM articles WHERE category_id = 123 ORDER BY id LIMIT 10000, 10;

可以看出,越往后分页,LIMIT语句的偏移量就会越大,速度也会明显变慢。此时,我们可以通过子查询的方式来提高分页效率:

1
2
3
SELECT * FROM articles WHERE id >=
(SELECT id FROM articles  WHERE category_id = 123 ORDER BY id LIMIT 10000, 1) 
AND category_id = 123 ORDER BY id LIMIT 10;

还可以通过JOIN方式来实现分页查询:

1
2
3
SELECT * FROM articles AS t1 
JOIN (SELECT id FROM articles WHERE category_id = 123 ORDER BY id LIMIT 10000, 1) AS t2 
WHERE t1.id >= t2.id AND t1.category_id = 123 ORDER BY t1.id LIMIT 10;

为什么会这样呢?因为子查询是在索引上完成的,而普通的查询时在数据文件上完成的,通常来说,索引文件要比数据文件小得多,所以操作起来也会更有效率。实际可以利用类似策略模式的方式去处理分页,比如判断如果是一百页以内,就使用最基本的分页方式,大于一百页,则使用子查询的分页方式。

参考:MySQL的分页查询SQL语句

This post is licensed under CC BY 4.0 by the author.