假如有一張100W左右數據的表,根據查詢條件進行分頁。如何分頁?

問題1:數據在實時發生變化,那麼,本來在第一頁看到的數據,因為後來又有數據插進來了,獲取第二頁數據的時候,也包含了部分第一頁的數據,也就是看到了重複的內容。

問題2:如果實現緩存的功能,一直實時查詢不是辦法,但根據頁數來緩存,也會造成另一種數據重複的問題。

請教下如何解決,謝謝。


不是什麼問題啊,很正常。

翻頁這種數據有一些變化完全不影響。


很簡單,翻頁不要用page,用index的方式,orderby ID desc,然後翻頁都是ID&<上一頁最後一條記錄的ID,limit 10條,但是要跳第n頁就不行了,權衡一下


我覺得可以給表緩存到內存里,也能提高效率不是?

可以設置一個隊列去保存這些表的內容,每次有數據插入的時候就同步更新這個隊列,把新增的數據放到隊尾,從隊頭開始根據index讀。如果有並發安全的需求的話,可以對隊列使用讀寫鎖。

大四菜逼狗,拋磚引玉


問題1:

這種情況應該使用瀑布流模式,而不是分頁模式……

不過如果列表是可變排序(比如知乎的回答,論壇的帖子),流模式有丟數據的可能

問題2:

當插入一條數據時,標記所有緩存失效,

當刪除一條數據時,標記該條數據頁及之後頁失效

另外,100W行數據的表,其實不需要緩存應該也不會太卡……


第一次只查主鍵,之後通過id查詢數據,通過id查詢的時候很容易緩存


1 從語句級別,我們可以給你的這段分頁讀,加上一個事務隔離,叫做serializable. 這個事務隔離級別,是可以防止「幻影讀」(Phantom Read)的。什麼叫「幻影讀」,就是你例子中的場景。你開始了一段事務,想在這段事務中,一直持續讀到事務一開始的那部分數據。 serializable 就幫你實現這個需求,靠的是用共享鎖鎖住符合條件的那些數據行,包括條件本身所在範圍的未被提交或者未來有可能會被提交的數據。這樣一來,並發就會受到影響,你肯定不願意這麼做。

2 100 W左右數據,如果伺服器內存夠大,你就塞進臨時表。這份數據副本就不會被更改了。想提高性能,你還可以用內存優化表,當然這另說。用臨時表就可以滿足了。

3 在你的查詢中,找到一張主表(如果是單表那就更好),增加一個timestamp. 在更新主表的時候,需要同時更新 timestamp. 這樣你的查詢一開始時候,就判斷只取 timestamp 比當前時間小的數據,取第二頁的時候,同樣也要判斷是否 timestamp 小於事務開始時候拿到的 timestamp.

/*--------------------------------------------------------

知友的提醒,讓我覺得有必要對第 1, 2 點做下補充說明:

*---------------------------------------------------------*/

第一點:用 serializable 的事務隔離級別,理論上可以實現題主的要求。但是這個實現的弊端是共享鎖會一直鎖定記錄,並且鎖定索引條件或者符合過濾條件範圍內的記錄,致使其他 session 一直不能新建或者更新記錄,造成等待,影響並發。故不推薦使用;

第二點:100 萬條數據,在給定的數據列寬度不明確的情況下,不好說到底佔用多少內存。如果是數據倉庫的事實表,那麼放進內存式優化表( SQL Server Memory Optimized Table), 會被壓縮。鑒於數據倉庫的維度數據同質化比較高,壓縮效率更好,實際上 100 W 條記錄,用到不 50-60 MB 就能被放進內存了。以現在的標配 128 G 內存來說,在並發量不大的 ERP/CRM/HR 系統中,也還是可以接受的。


這要看你的具體場景。如果你的條件選擇度很高,每次查詢都能從百萬的數據中選個幾百條出來,我覺得用資料庫索引和limit查詢就可以搞定了。數據量也不是很大。好好了解下索引。http://blog.csdn.net/yizhenn/article/details/52384611


問題1不是問題 ,因為有新數據所以第一頁的老數據才會到第二頁。這很正常,如果第一頁數據不會到第二頁才不正常


記住起始ID和當前頁碼就可以了。

另,如用戶回到第一頁,起始ID的作用就出來了。


用某個查詢條件縮小檢索範圍就行了


第一個問題,你是倒序列出來才會存在這樣的情況,那麼順序列出來就可以。非要一定倒序列出來的話,出現你說的前面第一頁看到的數據第二頁也出現,這個業務如此,跟生活的常理也是一樣啊。

第二個問題讀寫分離可以解決。即使是實時查也無可厚非,查詢的壓力都壓到讀庫了。


頁碼靠前直接mysql 的limit就可以了,頁碼較大的時候,延遲關聯自身,然後再通過limit方式過去數據。


這個不用解決吧。。。

方案:

數據:目標頁碼,當前頁碼,當前頁第一條數據ID,每頁條數

目標頁起點:(目標-當前)* 條數 + ID


1,select id,name,age,sex from table join (select id from table) a using(id) order by id asc limit x,x

2,if pageID &> pageCOUNT/2

select id,name,age,sex from table join (select id from table) a using(id) order by id desc limit x,x

僅供參考,


100w數據的表怎麼可能變的那麼快……


我假設你的每條新數據都是加到數據結構的開始 類似addFirst(),所以每次翻頁是第一頁的末尾可能會跑到第二頁的開始

那就直接將添加一個參數 hasNewData = true,然後再第二頁彈出一個pop-up說明有新數據。叫客戶自己重新刷新就好了 &>_&>。 何必考慮這麼多呢


你這個需求等於在看第一頁時就把範圍固定了,處理也不難,每次把最後一條記錄id傳回庫就是


推薦閱讀:

為什麼中國程序員對待外國人抱怨和對待國人抱怨採取截然不同的態度?
為什麼考慮到溢出用減法來比較更好?
Nginx支持ASP.net嗎?
為什麼mysql,nginx,libev,redis,linux都是用C寫的?

TAG:PHP | SQL | Java | Nginx | mongdb |