MySQL大資料量分頁查詢方法及其優化
方法1: 直接使用資料庫提供的SQL語句
語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N
適應場景: 適用於資料量較少的情況(元組百/千級)
原因/缺點: 全表掃描,速度會很慢 且 有的資料庫結果集返回不穩定(如某次返回1,2,3,另外的一次返回2,1,3). Limit限制的是從結果集的M位置處取出N條輸出,其餘拋棄.
方法2:建立主鍵或唯一索引, 利用索引(假設每頁10條)
語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 WHERE id_pk > (pageNum*10) LIMIT M
適應場景:
原因:索引掃描,速度會很快. 有朋友提出: 因為資料查詢出來並不是按照pk_id排序的,所以會有漏掉資料的情況,只能方法3
方法3: 基於索引再排序
語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 WHERE id_pk > (pageNum*10) ORDER BY id_pk ASC LIMIT M
適應場景: 適用於資料量多的情況(元組數上萬). 最好ORDER BY後的列物件是主鍵或唯一所以,使得ORDERBY操作能利用索引被消除但結果集是穩定的(穩定的含義,參見方法1)
原因: 索引掃描,速度會很快. 但MySQL的排序操作,只有ASC沒有DESC(DESC是假的,未來會做真正的DESC,期待...).
方法4: 基於索引使用prepare
第一個問號表示pageNum,第二個?表示每頁元組數
語句樣式: MySQL中,可用如下方法: PREPARE stmt_name FROM SELECT * FROM 表名稱 WHERE id_pk > (?* ?) ORDER BY id_pk ASC LIMIT M
適應場景: 大資料量
原因: 索引掃描,速度會很快. prepare語句又比一般的查詢語句快一點。
方法5: 利用MySQL支援ORDER操作可以利用索引快速定位部分元組,避免全表掃描
比如: 讀第1000到1019行元組(pk是主鍵/唯一鍵).
SELECT*FROMyour_tableWHEREpk>=1000ORDERBYpkASCLIMIT0,20
方法6: 利用"子查詢/連線+索引"快速定位元組的位置,然後再讀取元組.
比如(id是主鍵/唯一鍵,藍色字型時變數)
利用子查詢示例:
SELECT*FROMyour_tableWHEREid<=
(SELECTidFROMyour_tableORDERBYiddescLIMIT($page-1)*$pagesizeORDERBYiddesc
LIMIT$pagesize
利用連線示例:
SELECT*FROMyour_tableASt1
JOIN(SELECTidFROMyour_tableORDERBYiddescLIMIT($page-1)*$pagesizeASt2
WHEREt1.id <= t2.idORDERBYt1.iddescLIMIT$pagesize;
mysql大資料量使用limit分頁,隨著頁碼的增大,查詢效率越低下。
測試實驗
1. 直接用limit start, count分頁語句, 也是我程式中用的方法:
select*fromproductlimitstart,count
當起始頁較小時,查詢沒有效能問題,我們分別看下從10, 100, 1000, 10000開始分頁的執行時間(每頁取20條)。
如下:
select*fromproductlimit10,200.016秒
select*fromproductlimit100,200.016秒
select*fromproductlimit1000,200.047秒
select*fromproductlimit10000,200.094秒
我們已經看出隨著起始記錄的增加,時間也隨著增大, 這說明分頁語句limit跟起始頁碼是有很大關係的,那麼我們把起始記錄改為40w看下(也就是記錄的一般左右)
select*fromproductlimit400000,203.229秒
再看我們取最後一頁記錄的時間
select*fromproductlimit866613,2037.44秒
像這種分頁最大的頁碼頁顯然這種時間是無法忍受的。
從中我們也能總結出兩件事情:
limit語句的查詢時間與起始記錄的位置成正比
mysql的limit語句是很方便,但是對記錄很多的表並不適合直接使用。
2. 對limit分頁問題的效能優化方法
利用表的覆蓋索引來加速分頁查詢
我們都知道,利用了索引查詢的語句中如果只包含了那個索引列(覆蓋索引),那麼這種情況會查詢很快。
因為利用索引查詢有優化演算法,且資料就在查詢索引上面,不用再去找相關的資料地址了,這樣節省了很多時間。另外Mysql中也有相關的索引快取,在併發高的時候利用快取就效果更好了。
在我們的例子中,我們知道id欄位是主鍵,自然就包含了預設的主鍵索引。現在讓我們看看利用覆蓋索引的查詢效果如何。
這次我們之間查詢最後一頁的資料(利用覆蓋索引,只包含id列),如下:
selectidfromproductlimit866613,200.2秒
相對於查詢了所有列的37.44秒,提升了大概100多倍的速度
那麼如果我們也要查詢所有列,有兩種方法,一種是id>=的形式,另一種就是利用join,看下實際情況:
SELECT*FROMproductWHEREID> =(selectidfromproductlimit866613,1)limit20
查詢時間為0.2秒!
另一種寫法
SELECT*FROMproduct aJOIN(selectidfromproductlimit866613,20) bONa.ID = b.id
查詢時間也很短!
3. 複合索引優化方法
MySql 效能到底能有多高?MySql 這個資料庫絕對是適合dba級的高手去玩的,一般做一點1萬篇新聞的小型系統怎麼寫都可以,用xx框架可以實現快速開發。可是資料量到了10萬,百萬至千萬,他的效能還能那麼高嗎?一點小小的失誤,可能造成整個系統的改寫,甚至更本系統無法正常執行!好了,不那麼多廢話了。
用事實說話,看例子:
資料表 collect ( id, title ,info ,vtype) 就這4個欄位,其中 title 用定長,info 用text, id 是逐漸,vtype是tinyint,vtype是索引。這是一個基本的新聞系統的簡單模型。現在往裡面填充資料,填充10萬篇新聞。最後collect 為 10萬條記錄,資料庫表佔用硬1.6G。
OK ,看下面這條sql語句:
selectid,titlefromcollectlimit1000,10;
很快;基本上0.01秒就OK,再看下面的
selectid,titlefromcollectlimit90000,10;
從9萬條開始分頁,結果?
8-9秒完成,my god 哪出問題了?其實要優化這條資料,網上找得到答案。看下面一條語句:
selectidfromcollectorderbyidlimit90000,10;
很快,0.04秒就OK。 為什麼?因為用了id主鍵做索引當然快。網上的改法是:
selectid,titlefromcollectwhereid>=(selectidfromcollectorderbyidlimit90000,1)limit10;
這就是用了id做索引的結果。可是問題複雜那麼一點點,就完了。看下面的語句
select id from collect where vtype=1 order by id limit 90000,10; 很慢,用了8-9秒!
到了這裡我相信很多人會和我一樣,有崩潰感覺!vtype 做了索引了啊?怎麼會慢呢?vtype做了索引是不錯,你直接
selectidfromcollectwherevtype=1limit1000,10;
是很快的,基本上0.05秒,可是提高90倍,從9萬開始,那就是0.05*90=4.5秒的速度了。和測試結果8-9秒到了一個數量級。
從這裡開始有人提出了分表的思路,這個和dis #cuz 論壇是一樣的思路。思路如下:
建一個索引表: t (id,title,vtype) 並設定成定長,然後做分頁,分頁出結果再到 collect 裡面去找info 。 是否可行呢?實驗下就知道了。
10萬條記錄到 t(id,title,vtype) 裡,資料表大小20M左右。用
selectidfromtwherevtype=1orderbyidlimit90000,10;
很快了。基本上0.1-0.2秒可以跑完。為什麼會這樣呢?我猜想是因為collect 資料太多,所以分頁要跑很長的路。limit 完全和資料表的大小有關的。其實這樣做還是全表掃描,只是因為資料量小,只有10萬才快。OK, 來個瘋狂的實驗,加到100萬條,測試效能。加了10倍的資料,馬上t表就到了200多M,而且是定長。還是剛才的查詢語句,時間是0.1-0.2秒完成!分表效能沒問題?
錯!因為我們的limit還是9萬,所以快。給個大的,90萬開始
selectidfromtwherevtype=1orderbyidlimit900000,10;
看看結果,時間是1-2秒!why ?
分表了時間還是這麼長,非常之鬱悶!有人說定長會提高limit的效能,開始我也以為,因為一條記錄的長度是固定的,mysql 應該可以算出90萬的位置才對啊?可是我們高估了mysql 的智慧,他不是商務資料庫,事實證明定長和非定長對limit影響不大?怪不得有人說discuz到了100萬條記錄就會很慢,我相信這是真的,這個和資料庫設計有關!
難道MySQL 無法突破100萬的限制嗎???到了100萬的分頁就真的到了極限?
答案是: NO 為什麼突破不了100萬是因為不會設計mysql造成的。下面介紹非分表法,來個瘋狂的測試!一張表搞定100萬記錄,並且10G 資料庫,如何快速分頁!
好了,我們的測試又回到 collect表,開始測試結論是:
30萬資料,用分表法可行,超過30萬他的速度會慢道你無法忍受!當然如果用分表+我這種方法,那是絕對完美的。但是用了我這種方法後,不用分表也可以完美解決!
答案就是:複合索引! 有一次設計mysql索引的時候,無意中發現索引名字可以任取,可以選擇幾個欄位進來,這有什麼用呢?
開始的
selectidfromcollectorderbyidlimit90000,10;
這麼快就是因為走了索引,可是如果加了where 就不走索引了。抱著試試看的想法加了 search(vtype,id) 這樣的索引。
然後測試
selectidfromcollectwherevtype=1limit90000,10;
非常快!0.04秒完成!
再測試:
selectid,titlefromcollectwherevtype=1limit90000,10;
非常遺憾,8-9秒,沒走search索引!
再測試:search(id,vtype),還是select id 這個語句,也非常遺憾,0.5秒。
綜上:如果對於有where 條件,又想走索引用limit的,必須設計一個索引,將where 放第一位,limit用到的主鍵放第2位,而且只能select 主鍵!
完美解決了分頁問題了。可以快速返回id就有希望優化limit , 按這樣的邏輯,百萬級的limit 應該在0.0x秒就可以分完。看來mysql 語句的優化和索引時非常重要的!
擴充套件閱讀
微信公眾號:javafirst
掃碼關注免費獲取更多資源
來源:https://www.cnblogs.com/geningchao/p/6649907.html
相關推薦
MySQL大資料量分頁查詢方法及其優化 MySQL大資料量分頁查詢方法及其優化
MySQL大資料量分頁查詢方法及其優化 ---方法1: 直接使用資料庫提供的SQL語句---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適應場景: 適用於資料量較少的情況(元組百/千級) --
MySQL大資料量分頁查詢方法及其優化 ---方法1: 直接使用資料庫提供的SQL語句 ---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適
測試實驗 1. 直接用limit start, count分頁語句, 也是我程式中用的方法: select * from product limit start, count 當起始頁較小時,查詢沒有效能問題,我們分別看下從10, 100, 1000, 10000開始分頁的執行時間(每頁取20條), 如
MySQL大資料量分頁查詢方法及其優化
方法1: 直接使用資料庫提供的SQL語句 語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N 適應場景: 適用於資料量較少的情況(元組百/千級) 原因/缺點: 全表掃描,速度會很慢 且 有的資料庫結果集返回不穩定(如某次返回
MySQL大數據量分頁查詢方法及其優化
占用 對象 page 數據查詢 結果 sel 原因 希望 war ---方法1: 直接使用數據庫提供的SQL語句---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N---適應場景: 適用於數據量較少的情況(元組百/千級)--
解決mongodb大資料量分頁查詢效率問題
最常見的分頁採用的是skip+limit這種組合方式,這種方式對付小資料倒也可以,但是對付上幾百上千萬的大資料,只能力不從心,skip如果跳過大量的資料會很慢,並且會越查越慢,針對這一情況,可以通過條件查詢+排序+限制返回記錄,即 邊查詢,邊排序,排序之後,抽取上一頁中的最後一條記錄,作為當前分
mongodb大資料量分頁查詢效率問題
最常見的分頁採用的是skip+limit這種組合方式,這種方式對付小資料倒也可以,但是對付上幾百上千萬的大資料,只能力不從心,skip如果跳過大量的資料會很慢,並且會越查越慢。 //程式碼大概看下意思就行了 const list = db.getCollection('se
mysql 大資料量分頁優化
假設有一個千萬量級的表,取1到10條資料; select * from table limit 0,10; select * from table limit 1000,10; 這兩條語句查詢時間應該在毫秒級完成; select * from table limit
MySQL大資料量分頁SQL語句優化
分頁程式原理很簡單,這裡就不多說了,本篇文章主要說的是在資料表記錄量比較大的情況下,如何將分頁SQL做到更優化,讓MySQL執行的更快的方法。 一般的情況下,我們的分頁SQL語句是這樣的:
大資料量分頁優化--延遲查詢
延遲關聯 select * from it_area where name like '%東山%';+------+-----------+------+ | id | name | pid | +------+-----------+------+ |
通過索引,極大提高MySQL大資料量下的查詢效率
我在這裡測試了兩個表的左連線查詢,SQL語句是:select a.blog_id,a.blog_title,a.blog_thumb,a.blog_click,a.blog_addtime,a.blog_show,b.blog_category_name from `thin
SQL大資料量分頁效能優化
目前在進行web api只讀介面的改造,在改造過程中,發現改在後響應時間和之前區別不是很大,通過測試結果顯示在sql的分頁功能處找到原因,並對其進行優化,優化方案如下。測試內容此次執行時間對比採用平臺資金記錄最多的使用者 user_id 36062測試次數未5次 為避免索引
大資料量分頁儲存過程效率測試
我首先寫了五個常用儲存過程: 1,利用select top 和select not in進行分頁,具體程式碼如下: CREATE PROCEDURE Proc_paged_with_notin --利用select top and select n
mysql 大資料量時 limit查詢優化
一般,我們在做分頁時,用的是語句如下:select * from table LIMIT 5,10; #返回第6-15行資料但是,如果資料量很大,比如>1000萬,則利用以上的查詢會非常慢,可以利用以下語句進行優化:Select * From table Where I
sql2000,千萬級大資料量分頁儲存過程效率測試附程式碼
在專案中,我們經常遇到或用到分頁,那麼在大資料量(百萬級以上)下,哪種分頁演算法效率最優呢?我們不妨用事實說話。 測試環境 硬體:CPU 酷睿雙核T5750 記憶體:2G 軟體:Windows server 2003 + Sql server 2005 OK
Displaytag使用與應用displaytag完成大資料量分頁顯示的例子
Display Tag Lib是一個標籤庫,用來處理jsp網頁上的Table,功能非常強,可以對的Table進行分頁、資料匯出、分組、對列排序等等,反正我在做專案時需要的功能它都給我提供了,而且使用起來非常的方便。能夠大大減少程式碼量。 介個是Display Tag
MySQL大資料量快速分頁實現
以下分享一點我的經驗 一般剛開始學SQL語句的時候,會這樣寫 程式碼如下: SELECT * FROM table ORDER BY id LIMIT 1000, 10; 但在資料達到百萬級的時候,這樣寫會慢死 程式碼如下: SELECT * FROM tabl
提高MYSQL大資料量查詢的速度
1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t wher
大資料量表的查詢優化及索引使用
一、對於運算邏輯,儘可能將要統計的各專案整合在一個查詢語句中計算,而不是用分組條件或分專案呼叫多個查詢語句,而後在程式碼裡計算結果。 二、查詢語句的優化,諸如不用"select *"、多表關聯查詢時新增別名於查詢欄位上、避免使用in、not in關鍵字、非去除重複時用union all替換uni
MySQL分頁查詢性能優化
記錄 高並發 分頁查詢 容易 千萬 查詢方式 大數 測試的 業務 當需要從數據庫查詢的表有上萬條記錄的時候,一次性查詢所有結果會變得很慢,特別是隨著數據量的增加特別明顯,這時需要使用分頁查詢。對於數據庫分頁查詢,也有很多種方法和優化的點。下面簡單說一下我知道的一些方法。 準
mysql大資料量下優化
1 優化sql和索引2 增加快取如:redis3 主從複製或主主複製,讀寫分離4 利用mysql自帶分割槽表5 先做垂直拆分,將一個大系統分為多個小系統,也就是分散式6 水平切分,要選擇一個合理的sharding key,為了有好的查詢效率,表結構也要改動,做一定的冗餘,應用也要改,sql中儘量帶shardi