對這文章發表回應
發表限制: 非會員 可以發表
巧用SQL實現查詢的高效分頁
2019-11-10 由 網雲技術 發表于 程式開發
朋友們,我們學習和使用資料庫技術時,是否常常會感覺,SQL就那些基礎語法,掌握了自己基本都可以無所不能了。有些朋友可能會為自己的自負栽跟頭了,比如別人寫的查詢運行很快,而自己寫的速度卻非常慢。

簡單的SQL查詢隱藏了很深的玄機
表面看,不就是select查詢嘛,so easy,還有誰比誰更先進的。但事實卻總不是這樣,就算是簡單如select,都包含了無窮的玄機。
當然,導致查詢速度慢的原因有很多,比如主鍵的設置和使用、join的合理應用、只返回必要的欄位列表等等。這些查詢優化的方法可能一本書都寫不完。
我們今天要講的,主要是如何巧妙使用分頁技術加快查詢響應的速度。所謂分頁,當然是把海量的數據(比如1000萬條),按照固定的頁大小(比如1000條),根據需要分多次(比如1萬次)返回。

如果我們面對的數據行數只有幾十條數百條,分頁就沒有什麼明顯的意義了,但如果是數十萬、數百萬行呢,如果您不分頁一次性返回,有沒有必要另說,哪像蝸牛一樣的速度絕對會讓您懷疑人生。
特別是在手機APP中,我們一般通過手指上滑獲取更多(其實是下一頁)數據,完全不需要一次性完整返回。分頁速度快,用戶的體驗當然要更好。
還好主流的資料庫都支持分頁查詢,但不同資料庫的分頁方法稍有不同,下面著重講解下SQL Server、MySQL和PostgreSQL三種主流資料庫的分頁語法和具體應用。
SQL Server的專業分頁語法
SQL Server從2012版本開始,提供了一種專注於分頁查詢的語法支持,其語法格式為:
offset m rows fetch next n rows only
其中m的含義為記錄起始行前一條記錄的行標,n的含義為返回記錄的行數。

如果我們定義@pageindex為頁碼,@pagesize為頁大小,其常用的語法格式一般為:
select 欄位列表 from 表
order by 排序欄位
offset (@pageindex-1)*@pagesize rows fetch next @pagesize rows only;
這裡,頁碼@pageindex代表第幾頁(從1開始),頁大小@pagesize代表每頁的記錄條數。
SQL Server分頁語法應用案例
我這裡準備了一個有16萬條記錄的淘寶熱詞表,我們按每頁100條記錄查詢,測試下運行效果,腳本如下:
declare @pageindex int=1;
declare @pagesize smallint=100;
select t1.*
from dwordhot t1
order by isnull(t1.fhotcount,0) desc
{!-- PGC_COLUMN --}
offset (@pageindex-1)*@pagesize
rows fetch next @pagesize rows only;
運行效果如下:

分頁查詢耗用時間是33毫秒,如果不分頁,速度就差多了,如下圖所示:

完整查詢耗用時間15951毫秒,差別不是一般的大。對於大數據量查詢的情況,查詢不分頁,簡直就是自找苦吃。
MySQL的專業分頁語法
MySQL的查詢分頁的非常簡單,要用到limit關鍵字,其語法格式為:
limit m,n
其中m的含義為起始索引(從0開始),n的含義為取n條數據,結合頁碼和頁大小,其語法格式一般體現為:
select 欄位列表 from 表
limit (@pageindex-1)*@pagesize, @pagesize;

MySQL分頁比較簡潔易懂,這裡不再舉例。
pgSQL的專業分頁語法
PostgreSQL的查詢分頁也支持offset關鍵字,但語法格式與SQLServer不太相同,同時她也支持limit關鍵字,似乎是綜合了SQLServer和MySQL語法。其語法格式為:
limit n offset m
其中n的含義為獲取的記錄條數,m的含義為查詢的起點位置(從0開始),結合頁碼和頁大小,其語法格式一般體現為:

select 欄位列表 from 表
limit @pagesize offset (@pageindex-1)*@pagesize
pgSQL的分頁語法應用案例
我這裡準備了一張表snnavi,存入1萬條記錄,腳本如下:
do $$
declare
vtest integer := 1;
begin
while vtest < 10000 loop
vtest = vtest+1;
insert into snnavi(fncsid,fnaviid)
values ( 9501, vtest);
end loop;
end $$;
select * from snnavi;
查詢耗時結果參看下圖:

如果我們使用分頁的方式返回第一頁的100行,速度就飛快了,如下圖所示:

其它分頁方式
如果您的查詢數據量比較大,強烈建議您使用分頁技術,而且儘量採用專業的推薦分頁方式,既然是專業的,這效率肯定是槓槓的。
除了上述的專業方式,我們還可以使用其它非專業的分頁方式。比如在SQLServer中,使用top、row_number、over等關鍵字,也可以實現查詢分頁,使用得當時其運行的效率與專業模式相差無幾。
如果您有興趣了解,可參看我之前寫的文章《如何在SQLServer查詢中實現高效分頁》。

無論何種方法,既然要分頁,就要知道行的起點,根據起點結合top、order by等關鍵字截取相應區間的記錄。如果您的表設置有整數遞增欄位,使用
where id>=起點 and id<=終點
會更加直觀,但並不是所有的表我們都會這樣做,所以掌握專業的分頁語法還是非常必要
的。
原文出處:巧用SQL實現查詢的高效分頁 - 每日頭條