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
相信这是个大家都常见的问题,解决方式各自不一,欢迎交流,尤其是对分页有需求的
这种分页原理比普通的分页更聪明一些
谢谢分享.
但有时候分页会带很多条件... 减少扫描范围是个不错手段.
这东西理解起来并不难,看到这篇介绍前,同系统开发的一个数据库工程师聊过相应的
方法:
一是精确定位,就是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
评论列表