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的性能優化,特別是針對大數據的翻頁查詢。