11.order by 的工作原理2022-02-22

建表語句

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `city` varchar(16) NOT NULL,
  `name` varchar(16) NOT NULL,
  `age` int(11) NOT NULL,
  `addr` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `city` (`city`)
) ENGINE=InnoDB;

執(zhí)行sql

select city,name,age from t where city='杭州' order by name limit 1000  ;

一、全字段排序的原理

用explain sql語句會得到下圖


分析sql圖

圖中的Extra中的 Using filesort表示需要排序抖苦,MySQL會給每個線程分配一塊內(nèi)存用作排序叫做sort_buffer

1.上述排序sql在用全字段排序的流程

(1)初始化sort_buffer静陈,確定可以放入city击吱、name篮条、age三個字段;
(2)根據(jù)索引city性宏,找到第一個city=‘杭州’的主鍵id;
(3)根據(jù)主鍵id找到該行數(shù)據(jù)状飞,返回city毫胜、name、age到sort_buffer中昔瞧;
(4)依次尋找下一個主鍵id指蚁;
(5)循環(huán)執(zhí)行步驟3、4自晰,直到city != '杭州'為止凝化;
(6)把sort_buffer的數(shù)據(jù)根據(jù)name做快速排序;
(7)按照結果返回1000行給客戶端酬荞;

2.在MySQL中根據(jù)字段排序是在哪里進行的搓劫?

排序既可能只在內(nèi)存中進行瞧哟,也可能內(nèi)存和磁盤同時進行;

在哪里進行是由什么決定的枪向?
sort_buffer_size:排序時MySQL開辟的內(nèi)存大星诳;
如果sort_buffer_size大于需要排序參數(shù)的內(nèi)存秘蛔,就只在內(nèi)存排序陨亡;反之,就既在內(nèi)存排序深员,也會用磁盤空間輔助進行负蠕;

怎么看MySQL是否使用了磁盤空間輔助排序呢?

  /* 打開optimizer_trace倦畅,只對本線程有效 */
  SET optimizer_trace='enabled=on'; 

  /* @a保存Innodb_rows_read的初始值 */
  select VARIABLE_VALUE into @a from  performance_schema.session_status where variable_name =   'Innodb_rows_read';

  /* 執(zhí)行語句 */
  select city, name,age from t where city='杭州' order by name limit 1000; 

/* 查看 OPTIMIZER_TRACE 輸出 */
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G

/* @b保存Innodb_rows_read的當前值 */
select VARIABLE_VALUE into @b from performance_schema.session_status where variable_name = 'Innodb_rows_read';

/* 計算Innodb_rows_read差值 */
select @b-@a;

在查看OPTIMIZER_TRACE這步可以看出下圖:

OPTIMIZER_TRACE.png

number_of_tmp_files表示什么意思遮糖?
理解為什么是12,因為外部排序一般會使用歸并排序的算法叠赐,MySQL把需要排序的數(shù)據(jù)分成12份欲账,把每份單獨排序后存入磁盤的12個文件,最后合并成一個文件返回給客戶端芭概。
如果number_of_tmp_files的值為0赛不,則表示排序只在內(nèi)存進行。

examined_rows=4000表示什么意思谈山?
examined_rows=4000俄删,表示參與排序的行數(shù)是 4000 行

sort_mode 里面的 packed_additional_fields 的意思是?
說明排序的過程中對字符串做了緊湊處理奏路;按字符串的實際長度來分配空間畴椰。

select @b-@a 的返回結果是 4000表示什么?
表示整個執(zhí)行過程掃描的行數(shù)

怎么把internal_tmp_disk_storage_engine 設置成 MyISAM鸽粉?
internal_tmp_disk_storage_engine 這個參數(shù)是用來空值MySQL內(nèi)部在創(chuàng)建臨時表的時候斜脂,使用的默認存儲引擎是什么,這個參數(shù)可以配置為MyISAM或者InnoDB兩個触机。 5.7之后帚戳,默認的參數(shù)為InnoDB。

為什么InnoDB引擎select @b-@a 的返回結果是 4001儡首?

因為查詢 OPTIMIZER_TRACE 這個表時片任,需要用到臨時表,而 internal_tmp_disk_storage_engine 的默認值是 InnoDB蔬胯。如果使用的是 InnoDB 引擎的話对供,把數(shù)據(jù)從臨時表取出來的時候,會讓 Innodb_rows_read 的值加 1。

二产场、rowid排序

rowid排序會限制排序時單條數(shù)數(shù)據(jù)字段的總長度:例如

 SET max_length_for_sort_data = 16鹅髓;

意思就是如果返回的單條字段長度大于16,那么只會返回需要排序的字段和主鍵京景;以上例子中只會返回name窿冯、id;

1.rowid排序的執(zhí)行流程和全字段排序流程有什么區(qū)別确徙?

rowid排序的流程比全字段排序醒串,在數(shù)據(jù)庫取字段的時候只取name、id米愿;在排完序后厦凤,還會再到表里根據(jù)主鍵再查一次鼻吮,最終把結果返回給客戶端育苟。

2.為什么select @b-@a 這個語句的值變成 5000 了?

因為rowid排序比全字段排序多了回表里查詢的過程椎木。由于limit是1000违柏,所以多了1000。

3.sort_mode 變成了 <sort_key, rowid>香椎?

因為只用了這兩個字段漱竖。

4.number_of_tmp_files 變成 10 了?

因為需要進行排序的字段小了畜伐,所需要分配的空間也變小了馍惹。

三、全字段排序和rowid排序的比較玛界?

MySQL的原則是能盡量使用內(nèi)存排序就不要用磁盤万矾。如果實在是覺得內(nèi)存不夠用了才會用rowid排序,因為rowid排序會有增加的讀盤操作慎框,所以不推薦使用良狈。

四、優(yōu)化方案

1.優(yōu)化方案1笨枯,使用city薪丁、name的聯(lián)合索引

使用該方案的時候,只需要查找到滿足city='杭州'的記錄即可馅精,不需要進行排序严嗜,最后再用主鍵進行查找<=1000條的記錄即可。


引入 (city,name) 聯(lián)合索引后洲敢,查詢語句的執(zhí)行計劃

Extra 字段中沒有 Using filesort 了漫玄,也就是不需要排序了

2.進一步優(yōu)化方案,使用city沦疾、name称近、age的聯(lián)合索引

這個時候用到了覆蓋索引的優(yōu)化方案第队,覆蓋索引的概念是索引就已經(jīng)滿足查詢,不需要在回到主鍵索引去取數(shù)據(jù)刨秆。


引入 (city,name,age) 聯(lián)合索引后凳谦,查詢語句的執(zhí)行計劃

Extra 字段里面多了“Using index”,表示的就是使用了覆蓋索引

五衡未、思考題

假設你的表里面已經(jīng)有了 city_name(city, name) 這個聯(lián)合索引尸执,然后你要查杭州和蘇州兩個城市中所有的市民的姓名,并且按名字排序缓醋,顯示前 100 條記錄如失。如果 SQL 查詢語句是這么寫的 :

    mysql> select * from t where city in ('杭州',"蘇州") order by name limit 100;

那么,這個語句執(zhí)行的時候會有排序過程嗎送粱,為什么褪贵?如果業(yè)務端代碼由你來開發(fā),需要實現(xiàn)一個在數(shù)據(jù)庫端不需要排序的方案抗俄,你會怎么實現(xiàn)呢脆丁?進一步地,如果有分頁需求动雹,要顯示第 101 頁槽卫,也就是說語句最后要改成 “l(fā)imit 10000,100”, 你的實現(xiàn)方法又會是什么呢胰蝠?

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末歼培,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茸塞,更是在濱河造成了極大的恐慌躲庄,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翔横,死亡現(xiàn)場離奇詭異读跷,居然都是意外死亡,警方通過查閱死者的電腦和手機禾唁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門效览,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荡短,你說我怎么就攤上這事丐枉。” “怎么了掘托?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵瘦锹,是天一觀的道長。 經(jīng)常有香客問我,道長弯院,這世上最難降的妖魔是什么辱士? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮听绳,結果婚禮上颂碘,老公的妹妹穿的比我還像新娘。我一直安慰自己椅挣,他們只是感情好头岔,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鼠证,像睡著了一般峡竣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上量九,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天适掰,我揣著相機與錄音,去河邊找鬼娩鹉。 笑死攻谁,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的弯予。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼个曙,長吁一口氣:“原來是場噩夢啊……” “哼锈嫩!你這毒婦竟也來了?” 一聲冷哼從身側響起垦搬,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤呼寸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后猴贰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體对雪,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年米绕,在試婚紗的時候發(fā)現(xiàn)自己被綠了瑟捣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡栅干,死狀恐怖迈套,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碱鳞,我是刑警寧澤桑李,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響贵白,放射性物質發(fā)生泄漏率拒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一禁荒、第九天 我趴在偏房一處隱蔽的房頂上張望俏橘。 院中可真熱鬧,春花似錦圈浇、人聲如沸寥掐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽召耘。三九已至,卻和暖如春褐隆,著一層夾襖步出監(jiān)牢的瞬間污它,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工庶弃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留衫贬,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓歇攻,卻偏偏與公主長得像固惯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缴守,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容