a mysql php
a) 查询前n条记录 select * from table_name limit 0,n b) 查询第n条到第m条 select * from table_name limit n,m
b oracle html
a)查询前n条记录 select * from table_name where rownum b)查询第m条到第n条记录: select * from (select a.*,a.rownum rn from table_name where rownum<n) where rn>mc sqlserver
a)查询前n条记录: select top n * from table_name; b)查询第n条到第m条记录: select top n * from (select top m * from table_name order by column_name) a order by column_name desc
对于rownum来讲它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段能够用于限制查询返回的总行数,并且rownum不能以任何表的名称做为前缀。 java
(1) rownum 对于等于某值的查询条件
若是但愿找到学生表中第一条学生的信息,可使用rownum=1做为条件。可是想找到学生表中第二条学生的信息,使用rownum=2结果查不到数据。由于rownum都是从1开始,可是1以上的天然数在rownum作等于判断是时认为都是false条件,因此没法查到rownum = n(n>1的天然数)。
SQL> select rownum,id,name from student where rownum=1;(能够用在限制返回记录条数的地方,保证不出错,如:隐式游标) mysql
(2)rownum对于大于某值的查询条件
若是想找到从第二行记录之后的记录,当使用rownum>2是查不出记录的,缘由是因为rownum是一个老是从1开始的伪列,Oracle 认为rownum> n(n>1的天然数)这种条件依旧不成立,因此查不到记录。 web
那如何才能找到第二行之后的记录呀。可使用如下的子查询方法来解决。注意子查询中的rownum必需要有别名,不然仍是不会查出记录来,这是由于rownum不是某个表的列,若是不起别名的话,没法知道rownum是子查询的列仍是主查询的列。
SQL>select * from(select rownum no ,id,name from student) where no>2; sql
(3)rownum对于小于某值的查询条件
若是想找到第三条记录之前的记录,当使用rownum<3是能获得两条记录的。显然rownum对于rownum<n((n>1的天然数)的条件认为是成立的,因此能够找到记录。
SQL> select rownum,id,name from student where rownum <3; 数据库
综上几种状况,可能有时候须要查询rownum在某区间的数据,那怎么办呀从上能够看出rownum对小于某值的查询条件是人为true的,rownum对于大于某值的查询条件直接认为是false的,可是能够间接的让它转为认为是true的。那就必须使用子查询。例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么咱们只能写如下语句,先让它返回小于等于三的记录行,而后在主查询中判断新的rownum的别名列大于等于二的记录行。可是这样的操做会在大数据集中影响速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2; 性能优化
(4)rownum和排序
Oracle中的rownum的是在取数据的时候产生的序号,因此想对指定排序的数据去指定的rowmun行数据就必须注意了。
SQL> select rownum ,id,name from student order by name; session
能够看出,rownum并非按照name列来生成的序号。系统是按照记录插入时的顺序给记录排的号,rowid也是顺序分配的。为了解决这个问题,必须使用子查询
SQL> select rownum ,id,name from (select * from student order by name); oracle
参考文档:http://blog.csdn.net/mantisxf/article/details/1684805
具体的语法为:
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offsetLIMIT 子句能够被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。若是给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1): 为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。
mysql> SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15 //为了检索从某一个偏移量到记录集的结束全部的记录行,能够指定第二个参数为 -1: mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last. //若是只给定一个参数,它表示返回最大的记录行数目: mysql> SELECT * FROM table LIMIT 5; //检索前 5 个记录行 //换句话说,LIMIT n 等价于 LIMIT 0,n。参考文档: http://www.phpweblog.net/peiyinjin/archive/2008/04/15/3199.html
Select a.* from ( select id from table b force index(ind_group_type_time) where b.id=1111 order by b.update_time desc limit xx, xx ) b, table a where a.id=b.id;
MySQL的limit工做原理就是先读取n条记录,而后抛弃前n条,读m条想要的,因此n越大,性能会越差。
优化前SQL: SELECT * FROM member ORDER BY last_active LIMIT 50,5
优化后SQL: SELECT * FROM member INNER JOIN (SELECT member_id FROM member ORDER BY last_active LIMIT 50, 5) USING (member_id)
分别在于,优化前的SQL须要更多I/O浪费,由于先读索引,再读数据,而后抛弃无需的行。而优化后的SQL(子查询那条)只读索引(Cover index)就能够了,而后经过member_id读取须要的列。
参考文档:http://willko.iteye.com/blog/670120
总页数=(总记录数-1)/每页显示的记录数 +1
好比:要求选取 tbllendlist 中 第3000页的记录,每一页100条记录。
select top 100 * from tbllendlist where fldserialNo not in ( select top 300100 fldserialNo from tbllendlist order by fldserialNo ) order by fldserialNo
或者:
SELECT TOP 100 * FROM tbllendlist WHERE (fldserialNo > (SELECT MAX(fldserialNo) FROM (SELECT TOP 300100 fldserialNo FROM tbllendlist ORDER BY fldserialNo) AS T)) ORDER BY fldserialNo
方法1执行速度比较快!
SELECT ... FROM ( SELECT ROW_NUMBER() OVER (ORDER BY ID asc) AS RowNum, ...... FROM TABLE_NAME ) AS T WHERE T.RowNum> 10 and T.RowNum<= 20或者
WITH DataList AS ( SELECT ROW_NUMBER() OVER (ORDER BY O.ID DESC)AS RowNum, ...... FROM ..... WHERE ...... ) SELECT ...... FROM DataList WHERE RowNum BETWEEN 10 AND 20
参考文档:http://callan.iteye.com/blog/422822
<form name="form" method="post" action="peopleAction.do"> <table width="400" height="20" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td width="400" valign="middle" bgcolor="#CCCCCC"> 共为<bean:write name="maxPage"/> <!-- 输出总记录数 --> 页 共有<bean:write name="pageNumber"/> <!-- 输出总分页 --> 条 当前为第<bean:write name="nonce"/>页 <!-- 输出当前页数 --> <logic:equal name="nonce" value="1"> 首页 </logic:equal> <logic:notEqual name="nonce" value="1"> <!-- 若是当前页码不等于1 --> <a href="people.do?i=0">首页</a> <!-- 提供首页超连接 --> </logic:notEqual> <logic:lessEqual name="maxPage" value="${nonce}"> <!-- 若是当前页码不小于总页数 --> 尾页 <!-- 不提供尾页超连接 --> </logic:lessEqual> <logic:greaterThan name="maxPage" value="${nonce}"> <!-- 若是当前页码小于总页数 --> <a href="people.do?i=<%=maxPage-1%>">尾页</a> <!-- 提供尾页超连接 --> </logic:greaterThan> <logic:equal name="nonce" value="1"> <!-- 若是当前页码等于1 --> 上一页 <!-- 不提供上一页超连接 --> </logic:equal> <logic:notEqual name="nonce" value="1"> <!-- 若是当前页码不等于1 --> <a href="people.do?i=<%=number-1%>">上一页</a> <!-- 提供上一页超连接 --> </logic:notEqual> <logic:lessEqual name="maxPage" value="${nonce}"> 下一页 </logic:lessEqual> <logic:greaterThan name="maxPage" value="${nonce}"> <!-- 若是当前页面小于总页数 --> <a href="people.do?i=<%=number+1%>">下一页</a> <!-- 提供下一页超连接 --> </logic:greaterThan> </td> </tr> </table> </form>
Hibernate 能够实现分页查询,例如:
从第2万条开始取出100条记录
Query q = session.createQuery("from Cat as c");; q.setFirstResult(20000);; q.setMaxResults(100);; List l = q.list();;
那么Hibernate底层如何实现分页的呢?实际上Hibernate的查询定义在net.sf.hibernate.loader.Loader这个类里面,仔细阅读该类代码,就能够把问题完全搞清楚。
Hibernate2.0.3的Loader源代码第480行如下:
if (useLimit); sql = dialect.getLimitString(sql);; PreparedStatement st = session.getBatcher();.prepareQueryStatement(sql, scrollable);;
public boolean supportsLimit(); { return true; } public String getLimitString(String sql); { StringBuffer pagingSelect = new StringBuffer(100);; pagingSelect.append(sql);; pagingSelect.append(" limit ?, ?");; return pagingSelect.toString();; }
这是net.sf.hibernate.dialect.MySQLDialect,MySQL的专用分页语句,再来看net.sf.hibernate.dialect.Oracle9Dialect:
public boolean supportsLimit(); { return true; } public String getLimitString(String sql); { StringBuffer pagingSelect = new StringBuffer(100);; pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");; pagingSelect.append(sql);; pagingSelect.append(" ); row_ where rownum <= ?); where rownum_ > ?");; return pagingSelect.toString();; }
Oracle采用嵌套3层的查询语句结合rownum来实现分页,这在Oracle上是最快的方式,若是只是一层或者两层的查询语句的rownum不能支持order by。
除此以外,Interbase,PostgreSQL,HSQL也支持分页的sql语句,在相应的Dialect里面,你们自行参考。
若是数据库不支持分页的SQL语句,那么根据在配置文件里面
#hibernate.jdbc.use_scrollable_resultset true
默认是true,若是你不指定为false,那么Hibernate会使用JDBC2.0的scrollable result来实现分页,看Loader第430行如下:
if ( session.getFactory();.useScrollableResultSets(); ); { // we can go straight to the first required row rs.absolute(firstRow);; } else { // we need to step through the rows one row at a time (slow); for ( int m=0; m<firstRow; m++ ); rs.next();; }
若是支持scrollable result,使用ResultSet的absolute方法直接移到查询起点,若是不支持的话,使用循环语句,rs.next一点点的移过去。
可见使用Hibernate,在进行查询分页的操做上,是具备很是大的灵活性,Hibernate会首先尝试用特定数据库的分页sql,若是没用,再尝试Scrollable,若是不行,最后采用rset.next()移动的办法。
在查询分页代码中使用Hibernate的一大好处是,既兼顾了查询分页的性能,同时又保证了代码在不一样的数据库之间的可移植性。
参考文档: http://www.iteye.com/topic/261
总结一下:数据库中mysql和oracle的分页写法都不一致,各个数据库有各自的特色。另外要注意下相关sql的性能优化,特别是针对大数据的翻页查询。