千万条数据,Stack Overflow是如何实现快速分页的
轉載自?千萬條數據,Stack Overflow是如何實現快速分頁的
Stack Overflow 在分頁機制中使用頁碼代替偏移量,頁碼指向基于 LIMIT 和 OFFSET 的查詢。假設要對 1000 萬條記錄進行分頁,跳到最后一頁會非常慢,但 Stack Overflow 還是想辦法實現了快速分頁。
那么 Stack Overflow 是如何實現快速分頁的呢?緩存熱門查詢并在應用程序代碼中實現分頁?還是使用了什么數據庫黑魔法?
實際上,整個分頁過程是非常復雜的。但我會嘗試以一種簡單的方式告訴你其中的原理,而不是寫一個包含很多頁內容的帖子。
假設 ?
說到分頁,基本上是圍繞 pageNumber * pageSize 而展開的。也就是說,要在已排好序的 n 條記錄中獲得當前的集合,可以將 pageNumber 乘以 pageSize,然后再加上 pageSize,就可以返回當前結果。在我們的例子中,它實際上是(pageNumber - 1)* pageSize,因為頁面 1 的索引是 0。
在排序問題上,我們不需要完全排序整個集合,而是對 pageNumber * pageSize 條數據進行排序,這樣就可以得到當前頁面排好序的數據,而剩余部分可能只進行部分排序。與其排序整個集合并返回前 n 個結果,不如只對集合的前 n 個結果進行排序并返回這些結果。這樣做很合理。
另外需要注意的是,最耗資源的查詢總是那些中間頁。獲取最后 n 個頁面與獲得前 n 個頁面一樣容易:只需進行反向排序即可。比如,在按照日期降序排序時獲取 pageNumber 1 與在按照日期升序排列時獲取 pageNumber n-1 一樣,都很容易。很多排序引擎(數據庫、搜索引擎等)都使用了這種優化方式,我們也一樣。
為了方便討論,我們假定問題就是帖子,反之亦然,因為我會在文中交替使用這兩個名詞。
第 1 步:Tag Engine
我們有一個自己開發的.NET 應用程序,叫作 Tag Engine,它包含了帖子 ID 和元數據。我們把它看作是一個倒排索引,可以通過數據(如創建日期、標簽、分數等)查找帖子 ID。
Tag Engine 主要負責基于某些限制條件做一些集合操作,比如它對一系列帖子 ID 集合進行交集、聯合等操作,以便得到最終結果,并且還可以基于元數據在內存中進行排序。
我們使用 pageNumber 和 pageSize 以及一些限制條件(比如 Site ID,因為 Tag Engine 負責處理所有站點的查詢)向 Tag Engine 發起查詢。它在內存中進行集合操作(如聯合和交集),然后對結果進行排序,返回相關的帖子 ID 子集。
Tag Engine 還會緩存查詢結果(是集合,而不僅僅是請求的頁面),并且可以根據由查詢(頁碼、頁面大小、排序方式等)哈希生成的緩存鍵從特定的緩存結果集中快速選擇一個頁面。這樣極大提升了查詢性能。
第 2 步:數據庫
Tag Engine 不包含實際的數據,僅包含 ID 和元數據。因此,我們用帖子 ID 的結果集來查詢數據庫。查詢看起來像這樣:
Select p.*, pm.ViewCount, u.Id, u.ProfileImageUrl, ...From Posts pJoin PostMetadata pm On p.Id = pm.PostIdLeft Join Users u On p.LastActivityUserId = u.IdWhere p.Id In @Ids";這里的 @Ids 是指 Tag Engine 中包含的 ID 列表。這個查詢將返回實際的數據,但事情還沒完。
步驟 3:半冗余的內存排序
如上所述,Tag Engine 可能會返回緩存的數據。然而,就其性質而言,緩存數據不能保證準確性(因為它們有可能是過去狀態的快照)。相比之下,數據庫始終具有最新的數據。
為了解決這個問題,我們在內存中再次對結果頁面進行排序。
不過有一點比較讓人頭疼:最后一次內存排序基本上就是調用 List.Sort,并傳進去一個排序函數。排序函數因用戶查看不同的頁面而有所不同:對于“Newest”頁面,它會比較創建日期,而對于“Votes”,它會比較分數等。
如果我們沒有做最后一步,帖子在頁面上顯示時可能會出現亂序,因為它們在 Tag Engine 中的排序反映的是過去的狀態,而不是數據庫的當前狀態。
最后,我們把問題列表顯示出來!
原文鏈接:https://meta.stackoverflow.com/questions/322164/how-does-stack-overflow-do-pagination
總結
以上是生活随笔為你收集整理的千万条数据,Stack Overflow是如何实现快速分页的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win7开机显示配置已完成请勿关机卡住了
- 下一篇: java提高篇之抽象类与接口