老方法
传统分页查询,一般通过COUNT()函数事先获知总记录数据$amount
select count(*) as amout from tbl_name where uid = 1
然后可以通过ceil($amount / $page_size) 最终可以求知一共有多少页,告之用户。
具体实现,我这里就不再赘述了。
新方法
随着越来越非富的UI表现方式,用户并不观注有多少页,比如,一些社区游戏的好友列表常常不关注总页数,只管上下翻页
基本这种表现,我们没有必要浪费一条COUNT(*)查询。新办法其实很简单,不去统计总页数,而告诉客户端是否到达了最后一页。要告诉客户端是否到达了最后一页,只需要每次多查询一行记录。
function page_friend($page = 1, $page_size = 8) { global $user; if ($page < 1) { $page = 1; } //$page_size + 1,多取一行记录 $result = db_query( "SELECT * FROM friends WHERE uid = %d ORDER BY fuid LIMIT %d, %d", array($user->uid, ($page - 1) * $page_size, $page_size + 1) ); $friends = array(); while ($f = db_fecth_object($result)) { $friends[] = $f; } $page_is_last = true; if (count($friends) >= $page_size + 1) { $page_is_last = false; array_pop($friends); } return array( 'page' => $page, 'page_size' => $page_size, 'page_is_last' => $page_is_last, 'items' => $friends ); }
缺点:不能够显示总页码数,不能随意翻到指定页,只能上下翻页。
优点:每次请求都省去了一条COUNT查询,节约了服务器资源。
能不能再快一点
- 当一个数据库表过于庞大,LIMIT offset, length中的offset值过大,则SQL查询语句会非常缓慢,你需增加order by,并且order by字段需要建立索引。
- 如果使用子查询去优化LIMIT的话,则子查询必须是连续的,某种意义来讲,子查询不应该有where条件,where会过滤数据,使数据失去连续性。
- 如果你查询的记录比较大,并且数据传输量比较大,比如包含了text类型的field,则可以通过建立子查询。
SELECT id,title,content FROM items WHERE id IN (SELECT id FROM items ORDER BY id limit 900000, 10); - 如果limit语句的offset较大,你可以通过传递pk键值来减小offset = 0,这个主键最好是int类型并且auto_increment
SELECT * FROM users WHERE uid > 456891 ORDER BY uid LIMIT 0, 10;
这条语句,大意如下:
SELECT * FROM users WHERE uid >= (SELECT uid FROM users ORDER BY uid limit 895682, 1) limit 0, 10; - 如果limit的offset值过大,用户也会翻页疲劳,你可以设置一个offset最大的,超过了可以另行处理,一般连续翻页过大,用户体验很差,则应该提供更优的用户体验给用户。
转载请注明:爱开源 » MySQL 分页查询优化 LIMIT与COUNT优化