Seek method pagination是最近流行的分頁概念。其核心思想是:再也不依賴index做爲偏移量,而是使用條件表達式做爲分頁的依據。具體原理我在這裏就再也不廢話了,感興趣的朋友能夠去搜一搜。sql
因爲「條件表達式」成爲了分頁依據,那麼如何準備分頁條件表達式(seek predicate)就成爲了關鍵。數據庫
首先,使用seek method pagination的前提條件是:必須是有序結果集。對應於SQL script即須要有order by子句。緩存
下面就是組織seek predicate時須要注意的問題了:
ide
一、order by的列(或多個列)中必須有一個包含全表惟一值的列(就是相似主鍵那樣的列,列中的值必須not null並且unique)。主鍵列就符合這一特徵。
post
二、order by中出現的列,也必須出如今where子句中,並且排列順序不能錯。好比,order by A asc, B asc, C asc,那麼where ... and (A, B, C) > (x, y, z)。where中能夠出現其餘與seek predicate無關的其餘predicate,但要保證order by中出現的column都要出如今where子句中;
spa
三、order by的列必須是同向的,不能夠order by A asc, B desc, C asc;postgresql
四、(A, B, C, ...) > (x, y, z, ...) 的邏輯運算符必須與order by中的方向對應起來。規則:遞歸
翻頁方向 |
order by方向 |
where中的seek predicate操做符 |
下一頁 |
ASC |
> |
DESC |
< |
|
上一頁 |
ASC |
< |
DESC |
> |
若是你的結果集順序是ASC,那麼,若是你想翻到下一頁,你的seek predicate應該用>做爲邏輯操做符;若是你想翻到上一頁,seek predicate的操做符應該是<。ip
若是你的結果集順序是DESC,那麼,若是你想翻到下一頁,seek predicate的操做符應該是<,反之,用>號。內存
Note1:
這裏須要注意一件事情,就是null值問題。以前說過,order by中至少要有一列爲not null unique,而order by中的其餘列則沒有這個要求,列值能夠爲null,能夠出現重複值。若是翻頁時,遊標正好指在當前頁的最後一行,且這一行中的order by的某個列包含null值,那麼就不能用>或<號來拼where條件子句了,要用is null 和 is not null.
如今where中的A、B、C、...都有了,那麼每次翻頁時,如何找到對應的x,y,z呢?
首先,第一屏。第一屏須要一個batch size(假設爲30),也就是每屏加載多少數據。因爲第一屏你不知道具體的x,y,z值,因此直接從「頭」讀取30條記錄。得到這30條記錄後,緊接着,把第30條記錄的A、B、C的值分別記下來,做爲x, y, z(假設第一批30條記錄的最後一條記錄的A='Yan' B='Male' C=1200。下一批30條數據的where子句中的seek predicate就應該爲:
select ... from ... where ... and (A, B, C) > ('Yan', 'Male', 1200) order by A, B, C limit 30;
執行上面的SQL會獲得下面一頁30條記錄(若是有30條的話),而後重複剛纔採集條件值的操做,例如,第二屏30條記錄的最後一條記錄的A='Ye' B='Male' C=335。將得到的新的x、y、z值從新拼成第三屏的SQL:
select ... from ... where ... and (A, B, C) > ('Ye', 'Male', 335) order by A, B, C limit 30;
執行上面的SQL會獲得下面一頁30條記錄(若是有30條的話)。如此往復,一直到數據所有加載完畢。
(A, B, C) > ('Ye', 'Male', 335)
這個東西是seek predicate,能夠理解爲condition offset。傳統分頁方式用的是index offset。傳統分頁方式下,你須要知道一共有多少條記錄,每屏顯示多少條(batch size),而後查詢出整個結果集(DBMS的緩存裏), 而後使用index offset偏移量skim offset行記錄後,開始讀取batch條記錄。全集查詢和skim的過程是很要命的。隨着你翻頁越日後,好比1000頁之後,skim速度就會越慢,內存開銷也會越大,數據庫負擔越重。
可是seek method分頁則不一樣,數據庫並不須要查詢出全部符合條件的數據,他只須要按照你的condition定位到符合condition的第一條記錄,而後日後讀取batch size條記錄,就完成了那個頁面的讀取。
目前不少數據庫都支持seek predicate的這種(A, B, C) op (x, y, z)寫法,而JPA還不支持。可是,咱們能夠根據所學的數學知識,將不等式變換一下方式,換成等效公式。
(A, B) > (x, y) = A>x OR (A=x AND B>y)
(A, B, C) > (x, y, z) = A>x OR (A=x AND (B>y OR (B=y AND C>z)))
以此類推,你能夠寫個遞歸來自動分解拼裝(A, B, C, ...) > (x, y, z, ...)
Tips:
若是遇到order by的列值存在null值,那麼,A>null OR (A=null AND B>y)。這種寫法在postgresql v9.4中是支持的。若是你的數據庫不支持,能夠將>null寫成A is not null OR (A is null AND B>y)