PostgreSQL、MySQL高效分頁方法探討

對於數據庫相關的業務,逃不過的數據分頁場景,不管是前臺分頁瀏覽仍是劃到頁面底部自動加載。對於分頁需求,各數據庫也提供了成熟的SQL支持,相似於Hibernate等ORM框架也集成了相關的方法。可是基於數據庫(框架)提供的分頁方法,咱們可否結合業務,提供更高效更優化的分頁方法呢?數據庫

基礎分頁技術

數據查詢語句中,和分頁相關的有兩個參數,分別是:api

  • Limit:查詢數據條數
  • OFFSET:查詢結果數據起始位置偏移量(跳過的行數)

MySQL中的語法:框架

SELECT fields_list FROM table_name  [ ORDER BY ... ]
[LIMIT offset, limit];

但這個語法不兼容PostgreSQL,兼容MySQL和PostgreSQL的語法爲:優化

SELECT fields_list FROM table_name [ ORDER BY ... ]
[ LIMIT {number | ALL} ] [ OFFSET number];

注:LIMIT和OFFSET都是可選字段。code

下文以第二種兼容的語法來進行描述。本文示例的數據庫表信息以下:
示例表爲訂單表,表名:orders,每頁顯示條數:10 page_siezeserver

查詢第一頁:索引

SELECT * FROM orders ORDER BY order_id
LIMIT 10 OFFSET 0;

查詢第二頁:開發

SELECT * FROM orders ORDER BY order_id
LIMIT 10 OFFSET 10;

查詢第n頁:get

SELECT * FROM orders ORDER BY order_id
LIMIT page_sieze OFFSET page_sieze * n;

分頁優化

若是熟悉Openstack API的開發人員會注意到,Openstack原生API採用了特殊的分頁方式:Openstack分頁以limitmarker兩個字段進行控制,limit控制每頁顯示數量,marker標識數據起始位置,即本分頁第一條數據的ID
以nova list的API爲例,官方對兩個字段的說明以下:
Nova List APIit

Limit字段說明

Requests a page size of items. Returns a number of items up to a limit value. Use the limit parameter to make an initial limited request and use the ID of the last-seen item from the response as the marker parameter value in a subsequent limited request.

Marker字段說明

The ID of the last-seen item. Use the limit parameter to make an initial limited request and use the ID of the last-seen item from the response as the marker parameter value in a subsequent limited request.

以上描述中的關鍵信息是:若是分頁查詢,返回的JSON格式中會包含marker字段,指示下一頁數據第一條數據的ID。另外這個API也存在一個限制,就是分頁時,只能瀏覽上一頁/下一頁,而不能跳頁。

不過借鑑這個思路,咱們能夠對某些場景的分頁查詢進行優化。
對於按需自動加載(劃到頁面底部自動加載更多內容)或者只提供上一頁/下一頁瀏覽模式的場景,能夠進行以下優化:

  1. 每次查詢數據時,咱們記錄最後一條數據的ID或最後更新時間(這個主要根據order by字段來肯定)
  2. 加載下一頁數據時,把本頁的最後一條數據ID做爲過濾條件。
  3. 加載上一頁數據時,則把本頁第一條數據ID做爲過濾條件。

查詢下一頁

SELECT * FROM orders WHERE order_id > page_last_id ORDER BY order_id
LIMIT page_sieze OFFSET 0;

查詢上一頁

SELECT * FROM orders WHERE order_id < page_first_id ORDER BY order_id
LIMIT page_sieze OFFSET 0;

小技巧:每次查詢數據時,多返回一條數據,即返回page_size + 1條數據,但顯示時去掉最後一條數據,經過這多出來一條數據,咱們能夠用來判斷數據是否還有下一頁

另外對於能夠跳轉到任意頁面的場景,也能夠進行優化,這種可跳轉場景,分頁顯示也是有限的,通常模式是第一頁/上一頁/當前頁先後10頁……/下一頁/最後一頁,也就是說,分頁時,數據是在必定範圍內(先後10頁)移動,能夠以當前頁數據爲基礎,對數據進行過濾,減小數據掃描範圍。
考慮orders表有10W條記錄,每頁顯示10條,當前頁碼爲1000時的場景,若是按照單獨limit和offset模式,offset=1W,也就是數據庫要掃碼1W條記錄。假如如今翻頁要從1000頁跳轉到1005頁,咱們以第1000頁最後一條數據ID爲過濾條件,offset跳過1001-1004的40條數據便可。

查詢1005頁

SELECT * FROM orders WHERE order_id > page_1000_last_id ORDER BY order_id
LIMIT page_sieze OFFSET page_size * 4;

這種方法相比基礎的分頁方式,只要order by字段是主鍵或索引字段,數據掃描的行數從1W多條降低到了幾十條,效率大大提高。

相關文章
相關標籤/搜索