IT技术博客大学习 共学习 共进步

Mysql中的分页写法

Incessant 2009-10-11 22:34:47 浏览 4,742 次
基本上分页都是通过两个sql来实现的,一个查询count(*),一个查询list,如下:

    mysql> select count(*) from test;

    +----------+

    | count(*) |

    +----------+

    | 2097152 |

    +----------+

    1 row in set (0.00 sec)

mysql> select * from test limit 10;

    +--------+------+

    | a | b |

    +--------+------+

    | 62599 | |

    | 158694 | |

    | 155279 | |

    | 233810 | |

    | 160137 | |

    | 221035 | |

    | 174371 | |

    | 242246 | |

    | 147503 | |

    | 257907 | |

    +--------+------+

    10 rows in set (0.00 sec)

    Mysql中引出了另外的分页实现方式,通过sql_calc_found_rows,found_rows()查询一次就可以实现,减少了数据库的调用次数。

    1.计算全部结果集合中有多少,这比不用LIMIT而再次运行问询要快,原因是结果集合不需要被送至客户端。

    mysql> select sql_calc_found_rows * from test limit 10;

    +--------+------+

    | a | b |

    +--------+------+

    | 62599 | |

    | 158694 | |

    | 155279 | |

    | 233810 | |

    | 160137 | |

    | 221035 | |

    | 174371 | |

    | 242246 | |

    | 147503 | |

    | 257907 | |

    +--------+------+

    10 rows in set (3.45 sec)

    2.直接取出count(*)总数

    mysql> select found_rows();

    +--------------+

    | found_rows() |

    +--------------+

    | 2097152 |

    +--------------+

    1 row in set (0.00 sec)

    sql_calc_found_rows 和 found_rows() 在当你希望限制返回的行数时很有用,你不需要再次根据count(*)取到结果集。最明显的例子就是Web 分页list分页脚本,使用found_rows() 你可以很容易确定剩下的结果需要多少其它的页。

    通过 found_rows()的有效行数是瞬时的,并且不用于越过SELECT sql_calc_found_rows语句后面的语句,你要是需要保留这个值。

    mysql> select sql_calc_found_rows * from ... ;

    mysql> set @rows = found_rows();

Mysql中翻页如何实现?

    通常分页比如论坛帖子,我们一般都会看好几页,比如这个帖子非常火,分页翻到了第100页,这种语句的实现方式:

    mysql> select * from test where a>10 limit 1000,10 ;

    +--------+------+

    | a | b |

    +--------+------+

    | 187673 | |

    | 187721 | |

    | 187760 | |

    | 187780 | |

    | 187816 | |

    | 187821 | |

    | 187827 | |

    | 187891 | |

    | 187893 | |

    | 187966 | |

    +--------+------+

    10 rows in set (0.01 sec)

    这么写的话通常需要扫描表的前1010行,大家都知道回表的代价是很大的,而随着翻页的增加,扫描的代价会越来越大,我们是否可以采取另外的实现方式。

    1.先根据索引去取出a,这个地方只能走索引

    mysql> select a from test where a>10 limit 1000,10 ;

    +--------+

    | a |

    +--------+

    | 187673 |

    | 187721 |

    | 187760 |

    | 187780 |

    | 187816 |

    | 187821 |

    | 187827 |

    | 187891 |

    | 187893 |

    | 187966 |

    +--------+

    10 rows in set (0.00 sec)

    2.根据取到的记录id再去回表

    mysql> select t1.* from test t1,(select a from test where a>10 limit 1000,10) t2 where t1.a=t2.a;

    这种实现方式只需要回表很少记录,因为取id是通过扫描来实现的,然后根据符合条件的记录数id来回表。

注:mysql中是不允许子查询中使用limit

    mysql> select * from test where a in(select a from test where a>10 limit 1000,10);

    ERROR 1235 (42000): This version of MySQL doesn\'t yet support \'LIMIT & IN/ALL/ANY/SOME subquery\'

建议继续学习

  1. MYSQL分页limit速度太慢优化方法 (阅读 5,702)
  2. 深入理解Linux内存管理机制(一) (阅读 4,884)
  3. 独创比百度、Google分页还强的分页类 (阅读 4,702)
  4. 合理使用MySQL的Limit进行分页 (阅读 3,921)
  5. 高效的MySQL分页 (阅读 3,761)
  6. 用Twitter的cursor方式进行Web数据分页 (阅读 3,141)
  7. 交互模式之分页还是加载? (阅读 3,001)