本人了解的分頁查詢

2021-09-06 12:30:10 字數 3977 閱讀 7715

1:mysql 是基於limit的:

select * from t_user where limit ?, ? ; 第乙個引數表示起始位置, 第二個引數表示頁面大小

2:orcal 是基於rownum的:

在oracle中,用sql來實現分頁有很多種實現方式,但有些語句可能並不是很通用,只能用在一些特殊場景之中;

首先來介紹我們工作中最常使用的一種實現方式:

select *

from (select row_.*, rownum rownum_

from (select *

from table1

where table1_id = xx

order by gmt_create desc) row_

where rownum <= 20)

where rownum_ >= 10;

其中最內層的查詢select為不進行翻頁的原始查詢語句,可以用自己的任意select sql替換;rownum <= 20和rownum >= 10控制分頁查詢的每頁的範圍。

分頁的目的就是控制輸出結果集大小,將結果盡快的返回;上面的sql語句在大多數情況擁有較高的效率,主要體現在where rownum <= 20這句上,這樣就控制了查詢過程中的最大記錄數。

上面例子中展示的在查詢的第二層通過rownum <= 20來控制最大值,在查詢的最外層控制最小值。而另一種方式是去掉查詢第二層的where rownum <= 20語句,在查詢的最外層控制分頁的最小值和最大值。此時sql語句如下,也就是要介紹的第二種實現方式:

select *

from (select a.*, rownum rn

from (select *

from table1

where table1_id = xx

order by gmt_create desc) a)

where rn between 10 and 20;

由於oracle可以將外層的查詢條件推到內層查詢中,以提高內層查詢的執行效率,但不能跨越多層。

對於第乙個查詢語句,第二層的查詢條件where rownum <= 20就可以被oracle推入到內層查詢中,這樣oracle查詢的結果一旦超過了rownum限制條件,就終止查詢將結果返回了。

而第二個查詢語句,由於查詢條件between 10 and 20是存在於查詢的第三層,而oracle無法將第三層的查詢條件推到最內層(即使推到最內層也沒有意義,因為最內層查詢不知道rn代表什麼)。因此,對於第二個查詢語句,oracle最內層返回給中間層的是所有滿足條件的資料,而中間層返回給最外層的也是所有資料。資料的過濾在最外層完成,顯然這個效率要比第乙個查詢低得多。

以上兩種方案完全是通過rownum來完成,下面一種則採用rowid和rownum相結合的方式,sql語句如下:

select *

from (select rid

from (select r.rid, rownum linenum

from (select rowid rid

from table1

where table1_id = xx

order by gmt_create desc) r

where rownum <= 20)

where linenum >= 10) t1,

table1 t2

where t1.rid = t2.rowid;

從語句上看,共有4層select巢狀查詢,最內層為可替換的不分頁原始sql語句,但是他查詢的字段只有rowid,而沒有任何待查詢的實際表字段,具體查詢實際字段值是在最外層實現的;

這種方式的原理大致為:首先通過rownum查詢到分頁之後的10條實際返回記錄的rowid,最後通過rowid將最終返回字段值查詢出來並返回;

和前面兩種實現方式相比,該sql的實現方式更加繁瑣,通用性也不是非常好,因為要將原始的查詢語句分成兩部分(查詢欄位在最外層,表及其查詢條件在最內層);

但這種實現在特定場景下還是有優勢的:比如我們經常要翻頁到很後面,比如10000條記錄中我們經常需要查9000-9100及其以後的資料;此時該方案效率可能要比前面的高;

因為前面的方案中是通過rownum <= 9100來控制的,這樣就需要查詢出9100條資料,然後取最後9000-9100之間的資料,而這個方案直接通過rowid取需要的那100條資料;

從不斷向後翻頁這個角度來看,第一種實現方案的成本會越來越高,基本上是線性增長,而第三種方案的成本則不會像前者那樣快速,他的增長只體現在通過查詢條件讀取rowid的部分;

當然,除了以上提了這些方案,我們還可以用以下的sql來實現:

select *

from table1

where table1_id not in   

(select table1_id from table1 where rownum <= 10)

and rownum <= 10;

select *

from table1

where rownum <= 20

minus

select * from table1 where rownum <= 10;

………………

注意:當rownum作為查詢條件時,他是在order by之前執行,所以要特別小心;

比如我們想查詢table1中按table1_id倒序排列的前10條記錄不能用如下的sql來完成:

select * from table1 where rownum <= 10 order by table1_id desc;

3:基於jdbc的分頁:

conn.preparestatement(sql,游標型別,能否更新記錄);

// 游標型別:

// resultset.type_forword_only:只進游標

// resultset.type_scroll_insensitive:可滾動。但是不受其他使用者對資料庫更改的影響。

// resultset.type_scroll_sensitive:可滾動。當其他使用者更改資料庫時這個記錄也會改變。

// 能否更新記錄:

// resultset.concur_read_only,唯讀

// resultset.concur_updatable,可更新

preparedstatement pstat = conn.preparestatement(sql,resultset.type_scroll_insensitive,resultset.concur_read_only);

preparedstatement.setmaxrows(((pageindex - 1) * pagesize) + pagesize);//查詢的最大行數

rs = preparedstatement.executequery();

rs.absolute((pageindex - 1) * pagesize + 1);//利用絕對定位定位到結果集的每頁第二條資料

rs.relative(-1);//利用結果集的相對定位定位到每頁的第一條資料

然後再便利rs即可。

也可以先查出來,然後利用rs.absolute(int row)

將指標移動到此 resultset 物件的給定行編號

利用迴圈來控制

4:hibernate hql的分頁:

query q = s.createquery(hql.tostring());

for (int i = 0; i < params.size(); ++i)

q.setfirstresult((currentpage - 1)*pagesize); //設定起始位置

q.setmaxresults(pagesize);//這只一面大小

我們不用管底層是什麼實現,hibernate會幫我們呼叫相應的實現。

python分頁查詢 分頁查詢

分頁 使用select查詢時,如果結果集資料量很大,比如幾萬行資料,放在乙個頁面顯示的話資料量太大,不如分頁顯示,每次顯示100條。要實現分頁功能,實際上就是從結果集中顯示第1 100條記錄作為第1頁,顯示第101 200條記錄作為第2頁,以此類推。因此,分頁實際上就是從結果集中 擷取 出第m n條...

Mysql 分頁查詢 快照 Mysql分頁查詢優化

select from orders history where type 8 limit 1000,10 該條語句將會從表 orders history 中查詢offset 1000開始之後的10條資料,也就是第1001條到第1010條資料 1001 id 1010 資料表中的記錄預設使用主鍵 一...

mysql 分頁查詢 失效 mysql分頁查詢

比如每頁10條,分頁查詢 語法 select from table limit offset,rows offset指定要返回的第一行的偏移量,rows第二個指定返回行的最大數目。初始行的偏移量是0 不是1 select from table limit 0,10 第一頁 select from t...