分頁效能
現在假如啊,主鍵為id且是自增的,並且是連續的(不存在斷點,),那麼,這個語句 select * from xx limit 20000,10 跟這句 select * from xx where id>20000 limit 10.
取出的是相同的結果,但是前者的效能要遠遠落後於後者。因為,前者雖然是取2萬往後的十條,但是,他是先取出2萬零10條,然後從結果中篩選出後十條。而後者是直接先定位到2萬條,然後再取後十條,也就是說,前者遍歷了2萬零10行資料,而後者精遍歷我們需要的那幾條 這就引出了分頁的效能的差異
就比如網站常見的每頁顯示十條資料,那我們在選擇sql語句的時候,就不應該這樣了:
第一頁顯示的資料:
select * from xx limit 0,10
第二頁顯示的資料:
select * from xx limit 10,10
第3頁顯示的資料:
select * from xx limit 20,10
這樣隨著顯示的頁數越來越大,查詢效能直線下降。
我們需要這樣:
第一頁顯示的資料:
select * from xx where id >00 limit 10
第二頁顯示的資料:
select * from xx where id>10 limit 10
第3頁顯示的資料:
select * from xx where id >20 limit 10
第n頁:
select * from xx where id>(n-1)*10 limit 10
但是這樣還有一個問題:
我們前面假設了,id是連續的,但實際上,Id是不連續的,比如要顯示的是一個個人主頁的微博,每頁同樣是顯示10條微博,他不可能一直是寫,他也可能把過去的某條微博給刪除了,那麼這個時候這條資料刪除了,id也不存在了,id也就不連續了,所以會出現這樣,第二頁的起始id可能是11,然後結束id變為了56.也就是說,對於多少多少頁,我們是無法立刻預知到這一頁的起始id和結束Id,那麼select * from xx where id>(n-1)*10 limit 10.這樣的語句顯然就不行了.如果訪客直接要訪問第200頁,那麼我們還得計算200頁的起始id
計算起始id:
select id from xx limit 2000,1
有人會問了,你這個計算起始id,跟前面的第一種方案的分頁不一樣嗎?不一樣的,第一種方案是select * ,而這個只取id,如果是隻取索引,這種只需要查索引表就能查到,叫做覆蓋索引。覆蓋索引是select的資料列只用從索引中就能夠取得,不必讀取資料行
(關於索引的原理的知識點:select * from xx where id=2;他的執行過程是先讀取索引表,拿到id為2的物理指標,然後拿著這個指標,然後再到資料庫中獲取資料,)
那麼這種效率也是快的。
拿到第200也的起始值在進行查詢,兩個步驟用一條sql語句合起來就是:
select * from xx where id>(select id from xx limit 2000,1) limit 10
那麼這樣就實現了分頁查詢的效果。
但我們經常能看到,人家不光有頁數,還有上一頁,後一頁,那麼這個時候,就需要在程式碼中儲存當前頁面的最小id和最大id
當訪客檢視後一頁的時候,執行sql
select * from xx where id > max_id limit 10;
當訪客檢視前一頁的時候,執行sql
select * from xx where id < min_id order by id desc limit 10;