oracle,mysql,SqlServer三種數據庫的分頁查詢總結
- 數據庫
- 分頁查詢語句
- 說明
- MySql
- "QUERY_SQL limit ?,?"
- 使用limit關鍵字,第一個"?"是起始行號,
- 第二個"?"是返回條目數
- Oracle
- SELECT * FROM
- ( SELECT A.*, ROWNUM RN FROM
- (QUERY_SQL ) A WHERE ROWNUM
- <= ?) WHERE RN >= ?
- 結合rownum關鍵字,利用嵌套三層select
- 語句實現。第一個"?"表示終止行號,
- 第二個"?"表示其實行號
- Sql Server
- 尚無通用語句
- 可使用top n來返回前n條記錄或使用存儲過程
- DB2
- 假設查詢語句:select t1.* from t1 order
- by t1.id; 分頁語句可為:
- "select * from ( select rownumber() over
- (order by t1.id) as row_, t1.* from t1
- order by t1.id) as temp_ where row_
- between ?+1 and ?"
- 返回兩個"?"之間的記錄
- InterBase
- “QUERY_SQL row ? to ?”
- 返回兩個"?"之間的記錄
- PostgreSQL
- “QUERY_SQL limit ? offset ?”
- 第一個"?"為起始行號,第二個"?"代表
- 返回記錄數
MySql:
MySQL數據庫實現分頁比較簡單,提供了 LIMIT函數。一般只需要直接寫到sql語句後面就行了。
LIMIT子 句可以用來限制由SELECT語句返回過來的數據數量,它有一個或兩個參數,如果給出兩個參數, 第一個參數指定返回的第一行在所有數據中的位置,從0開始(注意不是1),第二個參數指定最多返回行數。例如:
select * from table LIMIT 10; #返回前10行
select * from table LIMIT 0,10; #返回前10行
select * from table limit 5,10
; #返回第6-15行數據 第一個參數是指要開始的地方,第二個參數是指每頁顯示多少條數據;注意:第一頁用0表示
Oracle:
考慮mySql中的實現分頁,select * from 表名 limit 開始記錄數,顯示多少條;就可以實現我們的分頁效果。
但是在oracle中沒有limit關鍵字,但是有 rownum字段
rownum是一個偽列,是oracle系統自動為查詢返回結果的每行分配的編號,第一行為1,第二行為2,以此類推。。。。
第一種:
代碼如下: SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21
其中最內層的查詢SELECT * FROM TABLE_NAME表示不進行翻頁的原始查詢語句。ROWNUM <= 40和RN >= 21控制分頁查詢的每頁的范圍。
上面給出的這個分頁查詢語句,在大多數情況擁有較高的效率。分頁的目的就是控制輸出結果集大小,將結果盡快的返回。在上面的分頁查詢語句中,這種考慮主要體現在WHERE ROWNUM <= 40這句上。
選擇第21到40條記錄存在兩種方法,一種是上面例子中展示的在查詢的第二層通過ROWNUM <= 40來控制最大值,在查詢的最外層控制最小值。而另一種方式是去掉查詢第二層的WHERE ROWNUM <= 40語句,在查詢的最外層控制分頁的最小值和最大值。
第二種:
代碼如下:
select * from (select e.*,rownum r from (select * from emp order by sal desc) e ) e1 where e1.r>21 and e1.r<=40;
紅色部分:按照工資降序排序並查詢所有的信息。
棕色部分:得到紅色部門查詢的值,並查詢出系統的rownum並指定上別名。這一句就比較關鍵,起了一個過渡的作用,首先要算出rownum來對紅色部分指定上序號,也可以為藍色外面部分用到這個變量。指定上查詢的開始記錄數和結束記錄的條件。
藍色部分:指定記錄從第幾條開始到第幾條結束,取出棕色部門的值來作為查詢條件的變量
總結:絕大多數的情況下,第一個查詢的效率比第二個高得多。
SqlServer:
分頁方案一:(利用Not In和SELECT TOP分頁)
語句形式:
代碼如下:
SELECT TOP 10 * FROM TestTable WHERE (ID NOT IN (SELECT TOP 20 id FROM TestTable ORDER BY id)) ORDER BY ID
SELECT TOP 頁大小 * FROM TestTable WHERE (ID NOT IN (SELECT TOP 頁大小*頁數 id FROM 表 ORDER BY id)) ORDER BY ID
分頁方案二:(利用ID大於多少和SELECT TOP分頁)
語句形式:
代碼如下:
SELECT TOP 10 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 20 id FROM TestTable ORDER BY id) AS T)) ORDER BY ID
SELECT TOP 頁大小 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 頁大小*頁數 id FROM 表 ORDER BY id) AS T)) ORDER BY ID
分頁方案三:(利用SQL的游標存儲過程分頁)
代碼如下:
create procedure XiaoZhengGe
@sqlstr nvarchar(4000), --查詢字符串
@currentpage int, --第N頁
@pagesize int --每頁行數
as
set nocount on
declare @P1 int, --P1是游標的id
@rowcount int
exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output
select ceiling(1.0*@rowcount/@pagesize) as 總頁數--,@rowcount as 總行數,@currentpage as 當前頁
set @currentpage=(@currentpage-1)*@pagesize+1
exec sp_cursorfetch @P1,16,@currentpage,@pagesize
exec sp_cursorclose @P1
set nocount off
其它的方案:如果沒有主鍵,可以用臨時表,也可以用方案三做,但是效率會低。
建議優化的時候,加上主鍵和索引,查詢效率會提高。
通過SQL 查詢分析器,顯示比較:結論是:
分頁方案二:(利用ID大於多少和SELECT TOP分頁)效率最高,需要拼接SQL語句
分頁方案一:(利用Not In和SELECT TOP分頁) 效率次之,需要拼接SQL語句
分頁方案三:(利用SQL的游標存儲過程分頁) 效率最差,但是最為通用
在實際情況中,要具體分析。
====================================================================
數據庫分頁大全(oracle利用解析函數row_number高效分頁)
Mysql分頁采用limt關鍵字
select * from t_order limit 5,10; #返回第6-15行數據 第一個參數是指要開始的地方,第二個參數是指每頁顯示多少條數據;注意:第一頁用0表示。
select * from t_order limit 5; #返回前5行
select * from t_order limit 0,5; #返回前5行
Mssql 2000分頁采用top關鍵字(20005以上版本也支持關鍵字rownum)
Select top 10 * from t_order where id not in (select id from t_order where id>5 ); //返回第6到15行數據
其中10表示取10記錄 5表示從第5條記錄開始取
Oracle分頁
①采用rownum關鍵字(三層嵌套)
SELECT *
FROM (
SELECT A.*,
ROWNUM num
FROM (
SELECT *
FROM t_order ) A
WHERE ROWNUM<=15 )
WHERE num>=5;
--返回第5-15行數據
②采用row_number解析函數進行分頁(效率更高)
SELECT xx.*
FROM(
SELECT t.*,row_number() over(
ORDER BY o_id)
AS num
FROM t_order t )xx
WHERE num
BETWEEN 5
AND 15; --返回第5-15行數據
解析函數能用格式
函數() over(pertion by 字段 order by 字段);
Pertion 按照某個字段分區
Order 按照勒個字段排序
分頁查詢
數據庫表結構及記錄如下:
1.根據rowid來分:
16:31:48 SQL> select * from passvehicleinfo p where rowid in ( select rid from (select rownum rn,rid from (select p.rowid rid,p.passvehicleid from passvehicleinfo p order by p.passvehicleid desc) view1 where rownum<10000) view2 where rn >9980)order by p.passvehicleid asc;
2.按分析函數來分
17:02:42 SQL> select * from (select p.*,row_number() over (order by p.passvehicleid desc ) rk from passvehicleinfo p) where rk>9980 and rk<10000;
3.按rownum來分
17:07:38 SQL> select * from (select view1.*,rownum rn from (select p.* from passvehicleinfo p order by p.passvehicleid desc) view1 where rownum<10000) view2 where rn>9980;
下面最主要介紹第三種:按rownum來分
1. rownum 分頁
SELECT * FROM emp;
2. 顯示rownum[oracle分配的]
SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e;
rn相當於Oracle分配的行的ID號
3.挑選出6—10條記錄
先查出1-10條記錄
SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e WHERE ROWNUM <= 10;
如果後面加上rownum>=6是不行的,
4. 然後查出6-10條記錄
SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e WHERE ROWNUM <= 10) WHERE rn >= 6;
5. 幾個查詢變化
a. 指定查詢列,只需要修改最裡層的子查詢
只查詢雇員的編號和工資
SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp)
e WHERE ROWNUM <= 10) WHERE rn >= 6;
b. 排序查詢,只需要修改最裡層的子查詢
工資排序後查詢6-10條數據
SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp ORDER
by sal) e WHERE ROWNUM <= 10) WHERE rn >= 6;
在顯示記錄條目時往往要用到分頁,一種常用的辦法是利用各種數據庫自帶的定位接口對原始查詢語句進行改寫,從而只取出特定范圍的某些記錄。不同的數據庫,查詢定位接口是不一樣的,下面做一匯總:
SQL Server
關於分頁 SQL 的資料許多,有的使用存儲過程,有的使用游標。本人不喜歡使用游標,我覺得它耗資、效率低;使用存儲過程是個不錯的選擇,因為存儲過程是顛末預編譯的,執行效率高,也更靈活。先看看單條 SQL 語句的分頁 SQL 吧。
方法1:
適用於 SQL Server 2000/2005
SELECT TOP 頁大小 * FROM table1 WHERE id NOT IN ( SELECT TOP 頁大小*(頁數-1) id FROM table1 ORDER BY id ) ORDER BY id
方法2:
適用於 SQL Server 2000/2005
SELECT TOP 頁大小 * FROM table1 WHERE id > ( SELECT ISNULL(MAX(id),0) FROM ( SELECT TOP 頁大小*(頁數-1) id FROM table1 ORDER BY id ) A ) ORDER BY id
方法3:
適用於 SQL Server 2005
SELECT TOP 頁大小 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1 ) A WHERE RowNumber > 頁大小*(頁數-1)
說明,頁大小:每頁的行數;頁數:第幾頁。使用時,請把“頁大小”以及“頁大小*(頁數-1)”替換成數碼。
MYSQL
SELECT * FROM TT LIMIT 1,20
SELECT * FROM TT LIMIT 21,30
/*
如果你是幾千上萬數據,就直接使用mysql自帶的函數 limit的普通用法就ok了,如果是100萬以上的數據,可能就要講方法了,下面我們來做個百萬級數據的分頁查詢語句.
mysql> select * from news where id>=(select id from news limit 490000,1) limit 10; //0.18 sec //很 明顯,這 種方式勝出 .
mysql> select * from news limit 490000,10 //0.22 sec;
*/
以下的文章主要介紹的是MySQL分頁的實際操作方案,其實關於實現MySQL分頁的最簡單的方法就是利用利用mysql數據庫的LIMIT函數,LIMIT [offset,] rows可以從MySQL數據庫表中第M條記錄開始檢索N條記錄的語句為:
SELECT * FROM 表名稱 LIMIT M,N
select * from sys_option limit 10,20
select * from table [查詢條件] order by id limit ?,?
Oracle
Oracle的分頁查詢語句基本上可以按照這篇了,下一篇文章會通過例子來申述。下面簡單討論一下多表聯合的情況。對最多見的等值表連接查詢,CBO 一般可能會采用兩種連接方式NESTED LOOP以及HASH JOIN(MERGE JOIN效率比HASH JOIN效率低,一般CBO不會考慮)。在這裡,由於使用了分頁,因此指定了一個歸回的最大記載數,NESTED LOOP在歸回記載數跨越最大值時可以頓時遏制並將結果歸回給中心層,而HASH JOIN必需處理完所有成集(MERGE JOIN也是)。那麼在大部分的情況下,對分頁查詢選擇NESTED LOOP作為查詢的連接方法具有較高的效率(分頁查詢的時候絕大部分的情況是查詢前幾頁的數據,越靠後面的頁數訪問概率越小)。
因此,如果不介意在體系中使用HINT的話,可以將分頁的查詢語句改寫為:
SELECT /*+ FIRST_ROWS */ * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21