【邮件讨论组】高效的mysql分页

jackxiang 2009-4-30 16:13 | |
http://chaoqun.17348.com/2009/04/efficient-pagination-using-mysql/

相信这是个大家都常见的问题,解决方式各自不一,欢迎交流,尤其是对分页有需求的
这种分页原理比普通的分页更聪明一些

谢谢分享.
但有时候分页会带很多条件... 减少扫描范围是个不错手段.
这东西理解起来并不难,看到这篇介绍前,同系统开发的一个数据库工程师聊过相应的
方法:

      一是精确定位,就是limit m,n  将m做好定位,减少磁盘扫描

      二是针对跨度一次多取,就目前的情况看,页面分页都是由限制的10页,或20
页,将10也或20页作为一组,一次取出。也能减少不小的消耗。

我们的情况可能会更复杂一些,比如datacache(mc)、pagecache(squid)等,在存
在cache的情况下,删cache也会带来一些小的问题。欢迎扩展话题。

见过gg的分页是带开始id和结束id的

直接给出page,无法知道上一次查询的id,可以改造一下必须查库的分页程序.

是不是说当m不写的时候会更快呢.也就是每次分页取上次分页的最后一个id,+1或-1.

直接limit n.

但话又说回来:

往往慢是因为count,count需要扫描全表.
重新学习了一下,找到两篇文档,分享一下:

http://www.mysqlperformanceblog.com/2007/04/10/count-vs-countcol/

http://imysql.cn/2008_06_24_speedup_innodb_count

其实有一个常量可以获取总条数的 SQL_CALC_FOUND_ROWS,不受limit 影响.
顺便请树新略微介绍一下SQL_CALC_FOUND_ROWS 吧。


以下是select 语句的语法:
SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr, ...
    [FROM table_references
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ...]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
    [INTO OUTFILE 'file_name' export_options
      | INTO DUMPFILE 'file_name'
      | INTO @var_name [, @var_name]]
    [FOR UPDATE | LOCK IN SHARE MODE]]

SQL_CALC_FOUND_ROWS 在查询的时候指定,查询完成后,再调用 select FOUND_ROWS()
获取满足条件的不受limit 影响的总行数.

总行数是在查询的同时计算的,再通过select FOUND_ROWS() 获取即可.



mysql 5手册上的说明:

SQL_CALC_FOUND_ROWS tells MySQL to calculate how many rows there would be in
the result set, disregarding any LIMIT clause. The number of rows can then
be retrieved with SELECT FOUND_ROWS().



用法:  select SQL_CALC_FOUND_ROWS  field1,field2,....  from table where
condition limit n,n+m;

    select FOUND_ROWS();

我认为这个 SQL_CALC_FOUND_ROWS 的功效与 count()没有太大的区别。

实验了一下:



mysql> select SQL_CALC_FOUND_ROWS id from wall_1c limit 1;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (26.29 sec)

mysql> select found_rows();
+--------------+
| found_rows() |
+--------------+
|      1847998 |
+--------------+
1 row in set (0.11 sec)


mysql> select id from wall_1c limit 1;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)



mysql> select count(id) from wall_1c ; //已经切换了机器,避免缓存的影响。
+-----------+
| count(id) |
+-----------+
|   1848008 |
+-----------+
1 row in set (17.93 sec)





以上是用的InnoDB Engine。



理论上说,SQL_CALC_FOUND_ROWS 也不会有什么先进的办法快速获取总条目数。



那个mysqlperformanceblog有过一篇关于SQL_CALC_FOUND_ROWS的测试

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not
-to-sql_calc_found_rows/

文章地结论:

obvious conclusion from this simple test is: when we have appropriate
indexes for WHERE/ORDER clause in our query, it is much faster to use two
separate queries instead of one with SQL_CALC_FOUND_ROWS.



当查询语句中的WHERE和ORDER的条件有合适的索引,选择两次查询而不是
SQL_CALC_FOUND_ROWS


这个问题是否可以这样理解,

如果需要结果集,那么通过SQL_CALC_FOUND_ROWS,先取得结果集,然后通过
SQL_FOUND_ROWS取得所得行数。如果不需要结果集,该用count就用count吧。

同时,需要关注count(col) 和 count(*) 的差别

我认为这个 SQL_CALC_FOUND_ROWS 的功效与 count()没有太大的区别。

实验了一下:



mysql> select SQL_CALC_FOUND_ROWS id from wall_1c limit 1;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (26.29 sec)

mysql> select found_rows();
+--------------+
| found_rows() |
+--------------+
|      1847998 |
+--------------+
1 row in set (0.11 sec)


mysql> select id from wall_1c limit 1;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)



mysql> select count(id) from wall_1c ; //已经切换了机器,避免缓存的影响。
+-----------+
| count(id) |
+-----------+
|   1848008 |
+-----------+
1 row in set (17.93 sec)





以上是用的InnoDB Engine。



理论上说,SQL_CALC_FOUND_ROWS 也不会有什么先进的办法快速获取总条目数。
那个mysqlperformanceblog有过一篇关于SQL_CALC_FOUND_ROWS的测试

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not
-to-sql_calc_found_rows/



文章地结论:

obvious conclusion from this simple test is: when we have appropriate
indexes for WHERE/ORDER clause in our query, it is much faster to use two
separate queries instead of one with SQL_CALC_FOUND_ROWS.



当查询语句中的WHERE和ORDER的条件有合适的索引,选择两次查询而不是
SQL_CALC_FOUND_ROWS


作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/1745/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2009-4-30 20:06
评论列表
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]