當需要從資料庫查詢的表有上萬條記錄的時候,一次性查詢所有結果會變得很慢,特別是隨著資料量的增加特別明顯,這時需要使用分頁查詢。對於資料庫分頁查詢,也有很多種方法和優化的點。下面簡單說一下我知道的一些方法。
準備工作
為了對下面列舉的一些優化進行測試,下面針對已有的一張表進行說明。
表名:order_history
描述:某個業務的訂單歷史表
主要字段:unsigned int id,tinyint(4) int type
字段情況:該錶一共37個字段,不包含text等大型陣列,最大為varchar(500),id欄位為索引,且為遞增。
資料量:5709294
mysql版本:5.7.16
線下找一張百萬級的測試表可不容易,如果需要自己測試的話,可以寫shell指令碼什麼的插入資料進行測試。
以下的 sql 所有語句執行的環境沒有發生改變,下面是基本測試結果www.cppcns.com:
select count(*) from orders_history;
返回結果:5709294
三次查詢時間分別為:
8903 ms
8323 ms
8401 ms
一般分頁查詢
一般的分頁查詢使用簡單的 limit 子句就可以實現。limit 子句宣告如下:
select * from table limit [offset,] rows | rows offset offset
limit 子句可以被用於指定 select 語句返回的記錄數。需注意以下幾點:
第乙個引數指定第乙個返回記錄行的偏移量
第二個引數指定返回記錄行的最大數目
如果只給定乙個引數:它表示返回最大的記錄行數目
第二個引數為 -1 表示檢索從某乙個偏移量到記錄集的結束所有的記錄行
初始記錄行的偏移量是 0(而不是 1)
下面是乙個應用例項:
select * from orders_history where type=8 limit 1000,10;
該條語句將會從表 orders_history 中查詢第1000條資料之後的10條資料,也就是第1001條到第10010條資料。
資料表中的記錄預設使用主鍵(一般為id)排序,上面的結果相當於:
select * from orders_history where type=8 order by id limit 10000,10;
三次查詢時間分別為:
3040 ms
3063 ms
3018 ms
針對這種查詢方式,下面測試查詢記錄量對時間的影響:
select * from orders_history where type=8 limit 10000,1;
select * from orders_history where type=8 limit 10000,10;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 10000,1000;
select * from orders_history where type=8 limit 10000,10000;
三次查詢時間如下:
查詢1條記錄:3072ms 3092ms 3002ms
查詢10條記錄:3081ms 3077ms 3032ms
查詢100條記錄:3118ms 3200ms 3128ms
查詢1000條記錄:3412ms 3468ms 3394ms
查詢10000條記錄:3749ms 3802ms 3696ms
另外我還做了十來次查詢,從查詢時間來看,基本可以確定,在查詢記錄量低於100時,查詢時間基本沒有差距,隨著查詢記錄量越來越大,所花費的時間也會越來越多。
針對查詢偏移量的測試:
select * fr orders_history where type=8 limit 100,100;
select * from orders_history where type=8 limit 1000,100;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 100000,100;
select * from orders_history where type=8 limit 1000000,100;
三次查詢時間如下:
查詢100偏移:25ms 24ms 24ms
查詢1000偏移:78ms 76ms 77ms
查詢10000偏移:3092ms 3212ms 3128ms
查詢100000偏移:3878ms 3812ms 3798ms
查詢1000000偏移:14608ms 14062ms 14700ms
隨著查詢偏移的增大,尤其查詢偏移大於10萬以後,查詢時間急劇增加。
這種分頁查詢方式會從資料庫第一條記錄開始掃瞄,所以越往後,查詢速度越慢,而且查詢的資料越多,也會拖慢總查詢速度。
使用子查詢優化
這種方式先定位偏移位置的 id,然後往後查詢,這種方式適用於 id 遞增的情況。
select * from orders_history where type=8 limit 100000,1;
select id from orders_history where type=8 limit 100000,1;
select * from orders_history where type=8 and
id>=(select id from orders_history where type=8 limit 100000,1)
limit 100;
select * from orders_history where type=8 limit 100000,100;
4條語句的查詢時間如下:
第1條語句:3674ms
第2條語句:1315ms
第3條語句:1327ms
第4條語句:3710ms
針對上面的查詢需要注意:
比較第1條語句和第2條語句:使用 select id 代替 select * 速度增加了3倍
比較第2條語句和第3條語句:速度相差幾十毫秒
比較第3條語句和第4條語句:得益於 select id 速度增加,第3條語句查詢速度增加了3倍
這種方式相較於原始一般的查詢方法,將會增快數倍。
使用 id 限定優化
這種方式假設資料表的id是連續遞增的,則我們根據查詢的頁數和查詢的記錄數可以算出查詢的id的範圍,可以使用 id between and 來查詢:
select * from orders_history where type=2 and id between 1000000 and www.cppcns.com1000100 limit 100;
查詢時間:15ms 12ms 9ms
這種查詢方式能夠極大地優化查詢速度,基本能夠在幾十毫秒之內完成。限制是只能使用於明確知道id的情況,不過一般建立表的時候,都會新增基本的id欄位,這為分頁查詢帶來很多遍歷。
還可以有另外一種寫法:
select * from orders_history whe程式設計客棧re id >= 1000001 limit 100;
當然還可以使用 in 的方式來進行查詢,這種方式經常用在多表關聯的時候進行查詢,使用其他表查詢的id集合,來進行查詢:
select * from orders_history whe id in (select order_id from trade_2 where goods = 'pen') limit 100;
這種 in 查詢的方式要注意:某些 mysql 版本不支援在 in 子句中使用 limit。
使用臨時表優化
這種方式已經不屬於查詢優化,這兒附帶提一下。
對於使用 id 限定優化中的問題,需要 id 是連續遞增的,但是在一些場景下,比如使用歷史表的時候,或者出現過資料缺失問題時,可以考慮使用臨時儲存的表來記錄分頁的id,使用分頁的id來進行 in 查詢。這樣能夠極大的提高傳統的分頁查詢速度,尤其是資料量上千萬的時候。
關於資料表的id說明
一般情況下,在資料庫中建立表的時候,強制為每一張表新增 id 遞增字段,這樣方便查詢。
如果像是訂單庫等資料量非常龐大,一般會進行分庫分表。這個時候不建議使用資料庫的 id 作為唯一標識,而應該使用分布式的高併發唯一 id 生成器來生成,並在資料表中使用另外的字段來儲存這個唯一標識。
使用先使用範圍查詢定位 id (或者索引),然後再使用索引進行定位資料,能夠提高好幾倍查詢速度。即先 select id,然後再 select *;
本文標題: mysql百萬級資料分頁查詢優化方案
本文位址:
mysql百萬級資料分頁查詢緩慢優化 實戰
畫面是這樣的 大概是這樣的 select count id from 查出總數 select from limit m,n 查出分頁資料 和前端的互動是這樣的 你傳給我查詢條件和pagenum pagesize 我給你返回total resultlist 恩,可以開始預估開發時間了 面對這麼多的資料...
mysql百萬級資料分頁查詢緩慢優化方法
參考 1 修改需求 一 與產品商討 修改需求 畫面是這樣的 大概是這樣的select count id from 查出總數 select from limit m,n 查出分頁資料 和前端的互動是這樣的你傳給我查詢條件和pagenum pagesize 我給你返回total resultlist 恩...
百萬級資料庫記錄下的Mysql快速分頁優化例項
點評 limit 1,111 資料大了確實有些效能上的問題,而通過各種方法給用上where id xx,這樣用上索引的id號可能速度上快點兒。by jack mysql limit分頁慢的解決辦法 mysql limit 優化,百萬至千萬條記錄實現快速分頁 mysql 效能到底能有多高?用了php半...