目前數據分頁一般分為兩種類型:傳統(tǒng)網站比較常見的電梯式分頁布局及移動端比較常見的流式分頁布局。
電梯式分頁布局在傳統(tǒng)網站中非常常見,比如百度、淘寶:
它的特點是在網站的底部有分頁欄,用戶不僅可以點擊上一頁、下一頁瀏覽數據,還可以直接點擊頁碼跳轉到特定頁,所以電梯式分頁的的 SQL 查詢(以下稱為傳統(tǒng)分頁)也比較統(tǒng)一,基本上為前端提供頁數及每頁的數量,后端套用下面的 SQL 查詢語句:
1 2
| #currentPage 為當前頁數(以 1 開始),pagingSize 為每頁的數據量 select * from ... where ... order by ... limit (currentPage- 1) * pagingSize, pagingSize;
|
流式分頁布局在移動端比較流行,因為移動端的屏幕尺寸普遍較小,會導致分頁欄不容易點擊。并且移動端擁有良好的滑動體驗,向上滑動加載更多,向下滑動刷新的操作方式更加便利。
在后端的處理上,傳統(tǒng)分頁邏輯是完全可以套用到流式分頁布局上的。并且因為不用提供總頁數或總數據量還能減少查詢次數,但是也會暴露出如下問題:
數據重復
比如:
數據缺失
效率低
使用 limit 在數據量小的時候并不會有效率問題,但是當數據偏移量很大時性能會開始急劇下降,查詢性能比對會在接下來提到。
綜上所述,流式分頁不需要也不適合使用傳統(tǒng)分頁,而是使用一種更合適的方法:游標分頁。
游標分頁舉例
假設有一個news_
表用來存放新聞信息,這個表的結構如下:
1 2 3 4 5 6 7 8 9
| # 新聞表,這個表可能還有一些別的字段,不過與主題無關就暫時省略掉了 create table news_ ( id_ int auto_increment comment 'id', title_ varchar (200) comment '標題', content_ text comment '正文', create_date datetime comment '創(chuàng)建日期', ... primary key (id_) );
|
眾所周知,大部分的軟件都會把最新的新聞放在最前面,這里我們假設刨除其他因素,單純以create_date
倒序排列,使用傳統(tǒng)分頁的 SQL 語句如下:
1 2
| #currentPage 為當前頁碼(以 1 開始),pagingSize 為每頁的數據量 select * from news_ order by create_date desc limit ($currentPage- 1) * $pagingSize, $pagingSize;
|
而游標分頁則不需要提供當前頁碼,而是提供當前頁的起始位置(也稱為游標)用于定位,游標分頁的 SQL 語句如下:
1 2
| #cursor 為上一頁最后一條新聞的 create_date(如果是第一頁則為當前時間),pagingSize 為每頁的數據量 select * from news_ where create_date
|
從這里可以看出,傳統(tǒng)分頁的偏移量是固定的,所以會因為數據的新增或減少導致接下來加載數據重復或丟失。而游標分頁則不會出現這種情況,因為當數據發(fā)生新增和減少時,游標的位置也會相對變化。
效率對比
之前提到傳統(tǒng)分頁在偏移量大時性能會急劇下降,而游標分頁則不會,在這里同樣以news_
表做個實驗。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| # 創(chuàng)建新聞表 drop table if exists news_; create table news_ ( id_ int auto_increment comment 'id', title_ varchar (200) comment '標題', content_ text comment '正文', create_date datetime comment '創(chuàng)建日期', primary key (id_) ); # 自動添加數據的存儲過程 create procedure insert_to_news () begin declare i int; set i = 0; while i
|
使用上面的 SQL 語句創(chuàng)建一個擁有 100w 條數據的news_
表,分別使用傳統(tǒng)分頁和游標分頁測試一下查詢效率:
1 2 3 4 5 6
| # 查詢時間:0.928s select * from news_ order by create_date desc limit 900000, 20; # 這里的 1911-05-01 20:06:57 是我生成數據中與上邊查詢對應的游標,請自行替換。 # 查詢時間:0.146s select * from news_ where create_date
|
可以看出在偏移量較大的情況下,即使沒有添加索引游標分頁的查詢時間都超越傳統(tǒng)分頁幾倍,而在添加了索引之后幾乎不會因為偏移量造成任何影響。
游標的另一種用法,更新新增數據
向新浪微博等軟件,當在主頁面放置一段時間后,就會收到提醒有 1 條新微博,點擊查看
,如果用戶點擊,則會將新增的數據添加到頂端。很明顯,這樣的操作也不是傳統(tǒng)分頁能夠實現的,所以大部分使用傳統(tǒng)分頁邏輯的程序在面對此需求時會直接清除所有內容,重新加載第一頁。
很顯然這并不是一個很好的方法,因為很有可能新增的數據只有 1、2 條,而為了這點數據刷新整頁是非常浪費的。此時如果使用游標則會輕松很多,同樣以news_
表舉例:
1 2 3 4 5
| # 獲得進入頁面后新增的新聞數,cursor 為當前頁面的第一條新聞的創(chuàng)建時間 select count (id_) from news_ where create_date > $cursor; # 如果新增的新聞數較小,點擊則只加載新增的新聞,cursor 為當前頁面的第一條新聞的創(chuàng)建時間 select * from news_ where create_date > $cursor order by create_date desc;
|
這樣便可以在新增量比較小的時候直接加載新增數據放在頁面頂部,在新增量較大時才選擇重新加載第一頁數據。
本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現有害或侵權內容,請
點擊舉報。