亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

【MySQL】order by 原理以及優化

發布時間:2020-08-13 13:38:55 來源:ITPUB博客 閱讀:177 作者:orclwujian 欄目:MySQL數據庫
一 簡介
   偏向于業務的(MySQL)DBA或者業務的開發者來說,order by 排序是一個常見的業務功能,將結果根據指定的字段排序,滿足前端展示的需求。然而排序操作也是經常出現慢查詢排行榜的座上賓。本文將從原理和實際案例優化,order by 使用限制等幾個方面來逐步了解order by 排序。
二 原理 
   在了解order by 排序的原理之前,強烈安利兩篇關于排序算法的文章 歸并排序的實現》  《經典排序算法MySQL 支持兩種排序算法,常規排序和優化,并且在MySQL 5.6版本中 針對order by limit M,N 做了特別的優化,這里列為第三種。
2.1 常規排序
  a 從表t1中獲取滿足WHERE條件的記錄
  b 對于每條記錄,將記錄的主鍵+排序鍵(id,col2)取出放入sort buffer
  c 如果sort buffer可以存放所有滿足條件的(id,col2)對,則進行排序;否則sort buffer滿后,進行排序并固化到臨時文件中。(排序算法采用的是快速排序算法)
  d 若排序中產生了臨時文件,需要利用歸并排序算法,保證臨時文件中記錄是有序的
  e 循環執行上述過程,直到所有滿足條件的記錄全部參與排序
  f 掃描排好序的(id,col2)對,并利用id去撈取SELECT需要返回的列(col1,col2,col3)
  g 將獲取的結果集返回給用戶。
從上述流程來看,是否使用文件排序主要看sort buffer是否能容下需要排序的(id,col2)對,這個buffer的大小由sort_buffer_size參數控制。此外一次排序需要兩次IO,一次是撈(id,col2),第二次是撈(col1,col2,col3),由于返回的結果集是按col2排序,因此id是亂序的,通過亂序的id去撈(col1,col2,col3)時會產生大量的隨機IO。對于第二次MySQL本身一個優化,即在撈之前首先將id排序,并放入緩沖區,這個緩存區大小由參數read_rnd_buffer_size控制,然后有序去撈記錄,將隨機IO轉為順序IO。
2.2 優化排序
    常規排序方式除了排序本身,還需要額外兩次IO。優化的排序方式相對于常規排序,減少了第二次IO。主要區別在于,放入sort buffer不是(id,col2),而是(col1,col2,col3)。由于sort buffer中包含了查詢需要的所有字段,因此排序完成后可以直接返回,無需二次撈數據。這種方式的代價在于,同樣大小的sort buffer,能存放的(col1,col2,col3)數目要小于(id,col2),如果sort buffer不夠大,可能導致需要寫臨時文件,造成額外的IO。當然MySQL提供了參數max_length_for_sort_data,只有當排序元組小于max_length_for_sort_data時,才能利用優化排序方式,否則只能用常規排序方式。
2.3 優先隊列排序
     為了得到最終的排序結果,無論怎樣,我們都需要將所有滿足條件的記錄進行排序才能返回。那么相對于優化排序方式,是否還有優化空間呢?5.6版本針對Order by limit M,N語句,在空間層面做了優化,加入了一種新的排序方式:優先隊列,這種方式采用堆排序實現。堆排序算法特征正好可以解limit M,N 這類排序的問題,雖然仍然需要所有元素參與排序,但是只需要M+N個元組的sort buffer空間即可,對于M,N很小的場景,基本不會因為sort buffer不夠而導致需要臨時文件進行歸并排序的問題。對于升序,采用大頂堆,最終堆中的元素組成了最小的N個元素,對于降序,采用小頂堆,最終堆中的元素組成了最大的N的元素。

三 優化
  通過上面的原理分析,我們知道排序的本質是通過一定的算法(耗費cpu 運算,內存,臨時文件IO)將結果集變成有序的結果集。如何優化呢?答案是分兩個方面利用索引的有序性(MySQL的B+ 樹索引是默認從小到大遞增排序)減少排序,最好的方式是直接不排序。
  1. create table t1(
  2.   id int not null primary key ,
  3.   key_part1 int(10) not null,
  4.   key_part2 varchar(10) not null default '',
  5.   key_part3
  6.   key idx_kp1_kp2(key_part1,key_part2,key_part4)
  7.   key idx_kp3(id)
  8. ) engine=innodb default charset=utf8
以下種類的查詢是可以利用到索引 idx_kp1_kp2的 
  1. SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
  2. SELECT * FROM t1 WHERE key_part1 = constant ORDER BY key_part2;
  3. SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
  4. SELECT * FROM t1 WHERE key_part1 = 1 ORDER BY key_part1 DESC, key_part2 DESC;
  5. SELECT * FROM t1 WHERE key_part1 > constant ORDER BY key_part1 ASC;
  6. SELECT * FROM t1 WHERE key_part1 < constant ORDER BY key_part1 DESC;
  7. SELECT * FROM t1 WHERE key_part1 = constant1 AND key_part2 > constant2 ORDER BY key_part2
溫馨提示 ,各位看官要辯證的看待官方給的例子,自己多動手實踐。
無法利用到索引排序的情況,其實我覺得這是本文的重點,對于廣大開發同學而言,記住那種不能利用索引排序會更簡單些。
  1. 1 最常見的情況 用來查找結果的索引(key2) 和 排序的索引(key1) 不一樣,where a=x and b=y order by id;
  2. SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
  3. 2 排序字段在不同的索引中,無法使用索引排序
  4. SELECT * FROM t1 ORDER BY key1,key2;
  5. 3 排序字段順序與索引中列順序不一致,無法使用索引排序,比如索引是 key idx_kp1_kp2(key_part1,key_part2)
  6. SELECT * FROM t1 ORDER BY key_part2, key_part1;
  7. 4 order by中的升降序和索引中的默認升降不一致,無法使用索引排序
  8. SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
  9. 5 ey_part1是范圍查詢,key_part2無法使用索引排序
  10. SELECT * FROM t1 WHERE key_part1> constant ORDER BY key_part2;
  11. 5 rder by和group by 字段列不一致
  12. SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2 group by key_part4;
  13. 6 索引本身是無序存儲的,比如hash 索引,不能利用索引的有序性。
  14. 7 order by字段只被索引了前綴 ,key idx_col(col(10))
  15. select * from t1 order by col ;
  16. 8 對于還有join的關聯查詢,排序字段并非全部來自于第一個表,使用explain 查看執行計劃第一個表 type 值不是const 。

當無法避免排序操作時,又該如何來優化呢?很顯然,優先選擇using index的排序方式,在無法滿足利用索引排序的情況下,盡可能讓 MySQL 選擇使用第二種單路算法來進行排序。這樣可以減少大量的隨機IO操作,很大幅度地提高排序的效率。
1 加大 max_length_for_sort_data 參數的設置
  在 MySQL 中,決定使用老式排序算法還是改進版排序算法是通過參數max_length_for_sort_data來決定的。當所有返回字段的最大長度小于這個參數值時,MySQL 就會選擇改進后的排序算法,反之,則選擇老式的算法。所以,如果有充足的內存讓MySQL 存放須要返回的非排序字段,就可以加大這個參數的值來讓 MySQL 選擇使用改進版的排序算法。
2 去掉不必要的返回字段
  當內存不是很充裕時,不能簡單地通過強行加大上面的參數來強迫 MySQL 去使用改進版的排序算法,否則可能會造成 MySQL 不得不將數據分成很多段,然后進行排序,這樣可能會得不償失。此時就須要去掉不必要的返回字段,讓返回結果長度適應 max_length_for_sort_data 參數的限制。
 同時也要規范MySQL開發規范,盡量避免大字段。當有select 查詢列含有大字段blob或者text 的時候,MySQL 會選擇常規排序。
"The optimizer selects which filesort algorithm to use. It normally uses the modified algorithm except when BLOB or TEXT columns are involved, in which case it uses the original algorithm.

3 增大 sort_buffer_size 參數設置
  這個值如果過小的話,再加上你一次返回的條數過多,那么很可能就會分很多次進行排序,然后最后將每次的排序結果再串聯起來,這樣就會更慢,增大 sort_buffer_size 并不是為了讓 MySQL選擇改進版的排序算法,而是為了讓MySQL盡量減少在排序過程中對須要排序的數據進行分段,因為分段會造成 MySQL 不得不使用臨時表來進行交換排序。但是這個值不是越大越好:
1 sort_buffer_size 是一個connection級參數,在每個connection第一次需要使用這個buffer的時候,一次性分配設置的內存。
2 sort_buffer_size 并不是越大越好,由于是connection級的參數,過大的設置+高并發可能會耗盡系統內存資源。
3 據說sort_buffer_size 超過2M的時候,就會使用mmap() 而不是 malloc() 來進行內存分配,導致效率降低。

四  參考文章
[1] MySQL order by 調優官方文檔 
[2] MySQL排序原理與案例分析   
[3] 淘寶MySQL 月報 
本文的原理分析部分 采取偷懶策略,直接從我的前同事 雁閑 的博客[2]摘抄了,強烈安利 雁閑的 博客 ,MySQL 源碼研究者,精通MySQL 業務和底層運維。
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

临漳县| 贡觉县| 灵山县| 陕西省| 大方县| 叶城县| 进贤县| 永靖县| 临海市| 汝城县| 遵义市| 淳安县| 封开县| 金塔县| 惠水县| 西吉县| 同心县| 江川县| 阳西县| 青铜峡市| 富川| 海晏县| 灵山县| 九江县| 吉林市| 彰化市| 沁阳市| 响水县| 泾川县| 渝中区| 万安县| 贡嘎县| 阿鲁科尔沁旗| 博客| 吉首市| 澳门| 兰考县| 武乡县| 江永县| 镇原县| 前郭尔|