數據查詢業務中,有時會碰到數據量很大的清單報表。因爲用戶輸入的查詢條件可能很寬泛,所以會從數據庫中查出幾百上千萬甚至過億行的記錄,常見的包括銀行流水記錄,物流明細等。呈現時若是等着把這些記錄所有檢索出來再生成報表,那會須要很長時間,用戶體驗天然會很是惡劣。並且,報表通常採用內存運算機制,大多數狀況下內存裏也裝不下這麼多數據。因此,咱們通常都會使用分頁呈現的方式,儘可能快速地呈現出第一頁,而後用戶能夠隨意翻頁顯示,每次只顯示一頁,也不會形成內存溢出。數據庫
傳統分頁呈現的實現,通常都會使用數據庫的分頁機制來作,利用數據庫提供的返回指定行號範圍內記錄的語法。界面端根據當前頁號計算出行號範圍(每頁顯示固定行數)做爲參數拼入 SQL 中,數據庫就會只返回當前頁的記錄,從而實現分頁呈現的效果。blog
不過,這樣作會有兩個問題:內存
1. 翻頁時效率較差get
用這種辦法呈現第一頁通常都會比較快,但向後翻頁時,所使用的取數 SQL 會被再次執行,而且將前面頁涉及的記錄跳過。對於有些沒有 OFFSET 關鍵字的數據庫,就只能由界面端自行跳過這些數據(取出後丟棄),而像 ORACLE 還須要用子查詢產生一個序號才能再用序號作過濾。這些動做都會下降效率,浪費時間,前幾頁還感受不明顯,但若是頁號比較大時,翻頁就會有等待感了。效率
2. 可能出現數據不一致用戶體驗
用這種辦法翻頁,每次按頁取數時都須要獨立地發出 SQL。這樣,若是在兩頁取數之間又有了插入、刪除動做,那麼取的數反映的是最新的數據狀況,極可能和原來的頁號匹配不上。例如,每頁 20 行,在第 1 頁取出後,用戶尚未翻第 2 頁前,第 1 頁包含的 20 行記錄中被刪除了 1 行,那麼用戶翻頁時取出的第 2 頁的第 1 行其實是刪除操做前的第 22 行記錄,而原來的第 21 行實際上落到第 1 頁去了,若是要看,還要翻回第 1 頁才能看到。若是還要基於取出的數據作彙總統計,那就會出現錯誤、不一致的結果。分頁
爲了克服這兩個問題,有時候咱們還會用另外一種方法,用 SQL 遊標從數據庫中取數,在取出一頁呈現後,但並不終止這個遊標,在翻下一頁的時候再繼續取數。這種方法能有效地克服上述兩個問題,翻頁效率較高,並且不會發生不一致的狀況。不過,絕大多數的數據庫遊標只能單向從前日後取數,表如今界面上就只能向後翻頁了,這一點很難向業務用戶交代,因此不多用這種辦法。語法
固然,咱們也能夠結合這兩種辦法,向後翻頁時用遊標,一旦須要向前翻頁,就從新執行取數 SQL。這樣會比每次分頁都從新取數的體驗好一些,但並無在根本上解決問題。 原文內容比較豐富,詳情請閱讀原文方法