gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

你真的了解MySQL的order by嗎

本篇文章給大家?guī)砹岁P(guān)于mysql中order by排序的相關(guān)知識,希望對大家有幫助。

你真的了解MySQL的order by嗎

排序這個詞,我的第一感覺是幾乎所有App都有排序的地方,淘寶商品有按照購買時間的排序、B站的評論有按照熱度排序的…,當(dāng)然我們今天說的并不是大數(shù)據(jù)下該如何優(yōu)雅的排序,如何提升排序性能的問題,我們說一說MySQL中的排序。

對于MySQL,一說到排序,你第一時間想到的是什么?關(guān)鍵字order by?order by的字段最好有索引?葉子結(jié)點(diǎn)已經(jīng)是順序的?還是說盡量不要在MySQL內(nèi)部排序?

事情的起因

現(xiàn)在假設(shè)有一張用戶的朋友表:

CREATE TABLE `user` (   `id` int(10) AUTO_INCREMENT,   `user_id` int(10),   `friend_addr` varchar(1000),   `friend_name` varchar(100),     PRIMARY KEY (`id`),   KEY `user_id` (`user_id`) ) ENGINE=InnoDB;

表中目前有兩個點(diǎn)需要關(guān)注下:

用戶的 user_id ,朋友的姓名 friend_name、朋友的地址 friend_addr

user_id 是有索引的

有一天,有個初級開發(fā)工程師小猿,收到了來自初級產(chǎn)品經(jīng)理小汪的需求:

小汪:小猿同志,現(xiàn)在需要在后臺加個功能,這個功能要支持根據(jù)用戶 id 能查到他所有的朋友姓名和地址,并且要求朋友的姓名是按照字典排序的。

小猿:好的,這個功能簡單,我馬上就上線。

于是小猿書寫了這樣的sql:

select friend_name,friend_addr from user where user_id=? order by name

在電光石火的瞬間,小猿趾高氣昂的上線了,這一切都很順利,直到有一天有個運(yùn)營同學(xué)導(dǎo)致了這樣的查詢:

select friend_name,friend_addr from user where user_id=10086 order by name

然而,這個查詢竟然比平時慢很多,數(shù)據(jù)庫報了慢查詢,小猿此時慌的一b:這是怎么回事?user_id 明明有索引啊,而且機(jī)智地我還只用了 select friend_name,friend_addr,并沒有用 select *呀。小猿此時不停地安慰自己,要淡定要淡定,然后突然想到有個explain命令,用explain來查看下那條sql的執(zhí)行計劃吧,當(dāng)小猿用了explain之后,發(fā)現(xiàn)extra字段里面有個看起來很危險的字眼:using filesort。

“這個查詢竟然用到了傳說中的文件排序,但是如果一個人朋友不是很多,就算了用了文件排序,應(yīng)該也很快吧”,除非這個user_id=10086的朋友很多,后來小猿去查了下,這個用戶的朋友竟然有10w多個~。

陷入了沉思的小猿心想:這個鍋看來是背定了,10w數(shù)據(jù)是有點(diǎn)大了,還有這個 using filesort 到底是怎么個排序原理?

解剖文件排序

有人可能說上面的問題是10w數(shù)據(jù)太大了,就算不排序也慢,這個其實(shí)是有道理的,10w數(shù)據(jù)一次性查出來,無論是MySQL內(nèi)存緩沖區(qū)的占用,還是網(wǎng)絡(luò)帶寬的消耗都是非常大的,那如果我加了limit 1000呢?網(wǎng)絡(luò)帶寬的問題肯定是解決了,因?yàn)閿?shù)據(jù)包整體變小了,但是 using filesort 的問題其實(shí)還是沒有解決,看到這里你可能會有疑問,using filesort 難道是在文件中排序的?在文件中到底是怎么排序的?或者我這樣問:如果給你來設(shè)計排序你會怎么處理?帶著這些疑問和思考我們來看看 using filesort 會涉及到哪些技術(shù)難點(diǎn)以及是如何解決的?

  • 首先我們的 user_id 是有索引的,所以會先在 user_id 索引樹上檢索我們的目標(biāo)數(shù)據(jù),即 user_id=10086 的數(shù)據(jù),但是我們要查詢的是 friend_name 和 friend_addr 字段,很不幸,光靠 user_id 索引是找不到這兩個字段值的

  • 于是需要回表,通過 user_id 對應(yīng)的主鍵去主鍵索引樹上去查找,ok,我們找到了第一條 user_id=10086 的 friend_name 和 friend_addr 字段

  • 這時該怎么辦?直接返回回去肯定不對,因?yàn)槲倚枰獙?friend_name 排序,如何排?數(shù)據(jù)都還沒找全,那么就得把查到的數(shù)據(jù)先放在一個地方,這個地方就是 sort_buffer,看到名字我想你應(yīng)該猜出來,沒錯,sort_buffer 就是用于這種情況下排序用的緩沖區(qū),這里需要注意的是每個線程都會有一個單獨(dú)的 sort_buffer,這么做的目的主要是為了避免多個線程對同一塊內(nèi)存進(jìn)行操作帶來鎖競爭的問題。

  • 當(dāng)?shù)谝粭l數(shù)據(jù)的 friend_name 和 friend_addr 已經(jīng)放入 sort_buffer 中,這當(dāng)然沒完,會一直重復(fù)同步的步驟,直至把所有 user_id=10086 的 friend_name 和 friend_addr 都放入到 sort_buffer 中才結(jié)束

  • sort_buffer 中的數(shù)據(jù)已經(jīng)放入完畢,接下來就該排序了,這里 MySQL 會對 friend_name 進(jìn)行快排,通過快排后,sort_buffer 中 friend_name 就是有序的了

  • 最后返回 sort_buffer 中的前1000條,結(jié)束。

你真的了解MySQL的order by嗎

一切看起來很絲滑,但是 sort_buffer 占用的是內(nèi)存空間,這就尷尬了,內(nèi)存本身就不是無限大的,它肯定是有上限的,當(dāng)然 sort_buffer 也不能太小,太小的話,意義不大。在 InnoDB 存儲引擎中,這個值是默認(rèn)是256K。

mysql> show variables  like 'sort_buffer_size'; +------------------+--------+ | Variable_name    | Value  | +------------------+--------+ | sort_buffer_size | 262144 | +------------------+--------+

也就是說,如果要放進(jìn) sort_buffer 中的數(shù)據(jù)是大于256K的話,那么采用在 sort_buffer 中快排的方式肯定是行不通的,這時候,你可能會問:MySQL難道不能根據(jù)數(shù)據(jù)大小自動擴(kuò)充嗎?額,MySQL是多線程模型,如果每個線程都擴(kuò)充,那么分給其他功能buffer就小了(比如change buffer等),就會影響其他功能的質(zhì)量。

這時就得換種方式來排序了,沒錯,此時就是真正的文件排序了,也就是磁盤的臨時文件,MySQL會采用歸并排序的思想,把要排序的數(shù)據(jù)分成若干份,每一份數(shù)據(jù)在內(nèi)存中排序后會放入臨時文件中,最終對這些已經(jīng)排序好的臨時文件的數(shù)據(jù)再做一次合并排序就ok了,典型的分而治之原理,它的具體步驟如下:

  • 先將要排序的數(shù)據(jù)分割,分割成每塊數(shù)據(jù)都可以放到 sort_buffer 中

  • 對每塊數(shù)據(jù)在 sort_buffer 中進(jìn)行排序,排序好后,寫入某個臨時文件中

  • 當(dāng)所有的數(shù)據(jù)都寫入臨時文件后,這時對于每個臨時文件而言,內(nèi)部都是有序的,但是它們并不是一個整體,整體還不是有序的,所以接下來就得合并數(shù)據(jù)了

  • 假設(shè)現(xiàn)在存在 tmpX 和 tmpY 兩個臨時文件,這時會從 tmpX 讀取一部分?jǐn)?shù)據(jù)進(jìn)入內(nèi)存,然后從 tmpY 中讀取一部分?jǐn)?shù)據(jù)進(jìn)入內(nèi)存,這里你可能會好奇為什么是一部分而不是整個或者單個?因?yàn)槭紫却疟P是緩慢的,所以盡量每次多讀點(diǎn)數(shù)據(jù)進(jìn)入內(nèi)存,但是不能讀太多,因?yàn)檫€有 buffer 空間的限制。

  • 對于 tmpX 假設(shè)讀進(jìn)來了的是 tmpX[0-5] ,對于 tmpY 假設(shè)讀進(jìn)來了的是 tmpY[0-5],于是只需要這樣比較:

如果 tmpX[0] < tmpY[0],那么 tmpX[0] 肯定是最小的,然后 tmpX[1] 和 tmpY[0] 比較,如果 tmpX[1] > tmpY[0],那么 tmpY[0] 肯定是第二小的…,就這樣兩兩比較最終就可以把 tmpX 和 tmpY 合并成一個有序的文件tmpZ,多個這樣的tmpZ再次合并…,最終就可以把所有的數(shù)據(jù)合并成一個有序的大文件。

你真的了解MySQL的order by嗎

文件排序很慢,還有其他辦法嗎

通過上面的排序流程我們知道,如果要排序的數(shù)據(jù)很大,超過 sort_buffer 的大小,那么就需要文件排序,文件排序涉及到分批排序與合并,很耗時,造成這個問題的根本原因是 sort_buffer 不夠用,不知道你發(fā)現(xiàn)沒有我們的 friend_name 需要排序,但是卻把 friend_addr 也塞進(jìn)了 sort_buffer 中,這樣單行數(shù)據(jù)的大小就等于 friend_name 的長度 + friend_addr 的長度,能否讓 sort_buffer 中只存 friend_name 字段,這樣的話,整體的利用空間就大了,不一定用得到到臨時文件。沒錯,這就是接下來要說的另一種排序優(yōu)化rowid排序。

rowid 排序的思想就是把不需要的數(shù)據(jù)不要放到 sort_buffer 中,讓 sort_buffer 中只保留必要的數(shù)據(jù),那么你認(rèn)為什么是必要的數(shù)據(jù)呢?只放 friend_name?這肯定不行,排序完了之后,friend_addr 怎么辦?因此還要把主鍵id放進(jìn)去,這樣排完之后,通過 id 再回次表,拿到 friend_addr 即可,因此它的大致流程如下:

  • 根據(jù) user_id 索引,查到目標(biāo)數(shù)據(jù),然后回表,只把 id 和 friend_name 放進(jìn) sort_buffer 中

  • 重復(fù)1步驟,直至全部的目標(biāo)數(shù)據(jù)都在 sort_buffer 中

  • 對 sort_buffer 中的數(shù)據(jù)按照 friend_name 字段進(jìn)行排序

  • 排序后根據(jù) id 再次回表查到 friend_addr 返回,直至返回1000條數(shù)據(jù),結(jié)束。

你真的了解MySQL的order by嗎

這里面其實(shí)有幾點(diǎn)需要注意的:

  • 這種方式需要兩次回表的

  • sort_buffer 雖然小了,但是如果數(shù)據(jù)量本身還是很大,應(yīng)該還是要臨時文件排序的

那么問題來了,兩種方式,MySQL 該如何選擇?得根據(jù)某個條件來判斷走哪種方式吧,這個條件就是進(jìn) sort_buffer 單行的長度,如果長度太大(friend_name + friend_addr的長度),就會采用 rowid 這種方式,否則第一種,長度的標(biāo)準(zhǔn)是根據(jù) max_length_for_sort_data 來的,這個值默認(rèn)是1024字節(jié):

mysql> show variables like 'max_length_for_sort_data'; +--------------------------+-------+ | Variable_name          | Value | +--------------------------+-------+ | max_length_for_sort_data | 1024  | +--------------------------+-------+

不想回表,不想再次排序

其實(shí)不管是上面哪種方法,他們都需要回表+排序,回表是因?yàn)槎壦饕蠜]有目標(biāo)字段,排序是因?yàn)閿?shù)據(jù)不是有序的,那如果二級索引上有目標(biāo)字段并且已經(jīng)是排序好的了,那不就兩全其美了嘛。

沒錯,就是聯(lián)合索引,我們只需要建立一個 (user_id,friend_name,friend_addr)的聯(lián)合索引即可,這樣我就可以通過這個索引拿到目標(biāo)數(shù)據(jù),并且friend_name已經(jīng)是排序好的,同時還有friend_addr字段,一招搞定,不需要回表,不需要再次排序。因此對于上述的sql,它的大致流程如下:

  • 通過聯(lián)合索引找到user_id=10086的數(shù)據(jù),然后讀取對應(yīng)的 friend_name 和 friend_addr 字段直接返回,因?yàn)?friend_name 已經(jīng)是排序好的了,不需要額外處理

  • 重復(fù)第一步驟,順著葉子節(jié)點(diǎn)接著向后找,直至找到第一個不是10086的數(shù)據(jù),結(jié)束。

你真的了解MySQL的order by嗎

聯(lián)合索引雖然可以解決這種問題,但是在實(shí)際應(yīng)用中切不可盲目建立,要根據(jù)實(shí)際的業(yè)務(wù)邏輯來判斷是否需要建立,如果不是經(jīng)常有類似的查詢,可以不用建立,因?yàn)槁?lián)合索引會占用

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
国产av熟女一区二区三区| 男人日女人逼逼| www.在线观看av| 五月天婷婷在线观看视频| 亚洲 高清 成人 动漫| 北条麻妃视频在线| 韩国日本在线视频| 九九九九免费视频| 黄色片视频在线免费观看| 欧美日韩福利在线| 日本中文字幕网址| av在线播放天堂| 欧美乱做爰xxxⅹ久久久| 青青草免费在线视频观看| 波多野结衣国产精品| 精品少妇无遮挡毛片| 能看的毛片网站| 日韩免费毛片视频| 久久综合久久网| 男的插女的下面视频| 国产精品一区二区免费在线观看| 搞av.com| 一区二区三区入口| 欧美日韩理论片| 国产精品三级一区二区| 阿v天堂2017| 三级在线视频观看| 色一情一乱一乱一区91| 亚洲色成人www永久在线观看 | 国产自偷自偷免费一区| 999在线免费视频| 极品粉嫩美女露脸啪啪| 一本—道久久a久久精品蜜桃| 少妇大叫太大太粗太爽了a片小说| www.日本少妇| 日本三区在线观看| 日本黄色播放器| 日韩av高清在线看片| 欧美性猛交xxx乱久交| 久久国产激情视频| 久久久国内精品| 国产视频一区二区三区在线播放| 国产成人精品免费看在线播放| 91国在线高清视频| 国产中文字幕免费观看| 99亚洲精品视频| 国产一区二区三区精彩视频| 欧美性猛交xxxx乱大交91| 成人毛片视频网站| 亚洲国产精品女人| 在线免费视频一区| 亚洲精品无码国产| 老司机午夜网站| 免费一区二区三区在线观看| 免费成人午夜视频| 日韩精品视频网址| 女同激情久久av久久| 欧美 日韩 激情| 中文字幕无码精品亚洲资源网久久| 艹b视频在线观看| 久久久久久久少妇| 成人在线观看你懂的| 日本人69视频| 奇米影音第四色| 日日摸日日碰夜夜爽av| 国产精品久久中文字幕| 午夜啪啪免费视频| 国产精品久久久久久久99| 国产精彩免费视频| 国产真人无码作爱视频免费| 五月丁香综合缴情六月小说| 亚洲 欧美 综合 另类 中字| 国产成人精品免费看在线播放| 日本中文字幕精品—区二区| xxx国产在线观看| 国产三级国产精品国产专区50| 欧美精品无码一区二区三区| 国内外成人激情视频| 国产男女激情视频| 男人亚洲天堂网| 亚洲欧美另类动漫| 少妇激情一区二区三区| 红桃视频 国产| 1314成人网| 隔壁人妻偷人bd中字| 你懂的av在线| 久久久久久久少妇| 五月六月丁香婷婷| 成人午夜视频免费观看| 人妻少妇被粗大爽9797pw| 久久婷婷国产精品| 一起操在线视频| 佐佐木明希av| 免费在线激情视频| 老司机久久精品| 男人天堂新网址| 精品一卡二卡三卡| 久久精品国产精品亚洲精品色| 中国女人做爰视频| 中文字幕乱码人妻综合二区三区 | 久久久精品麻豆| 手机在线观看日韩av| a√天堂在线观看| 九九九九九九九九| 国自产拍偷拍精品啪啪一区二区| 欧洲熟妇精品视频| 日本福利视频网站| 在线观看的毛片| 特级西西444| 亚洲免费黄色网| 日韩欧美视频网站| 黄色小视频大全| 超碰97人人射妻| 欧美中日韩在线| 中文字幕第38页| 超碰97人人射妻| 成人免费播放器| 婷婷视频在线播放| 久久久国产欧美| 激情综合在线观看| 久久福利一区二区| mm131国产精品| 别急慢慢来1978如如2| 日韩视频免费播放| 免费在线黄网站| 一级淫片在线观看| 日韩在线不卡一区| av网站在线不卡| 看欧美ab黄色大片视频免费 | www.99在线| 国产69精品久久久久久久| 久久久久久久久网| 91欧美一区二区三区| 亚洲视频在线不卡| www.色欧美| 四虎影院一区二区| 九九久久九九久久| 精品久久久无码人妻字幂| 爱爱爱视频网站| 国产精品国产三级国产专区51| 污污的视频免费| 久久久精品高清| 日本中文字幕在线不卡| 一级全黄肉体裸体全过程| 九九久久久久久| 最新中文字幕久久| 黄色录像特级片| 福利视频免费在线观看| 国产一区二区三区小说| 国产亚洲黄色片| 欧美成人精品欧美一级乱| 免费看a级黄色片| 又色又爽又高潮免费视频国产| 欧美精品第三页| www.com操| 日本丰满大乳奶| 日韩av片在线看| 嫩草影院国产精品| 久久久久久综合网| 免费网站在线观看视频 | 国产96在线 | 亚洲| 日韩网址在线观看| 亚洲激情在线看| 九一国产精品视频| 黑森林精品导航| www.在线观看av| 亚洲综合在线网站| 日韩video| 久草综合在线观看| 强开小嫩苞一区二区三区网站| 成人小视频在线观看免费| 精品久久久久久久免费人妻| 亚洲怡红院在线| 97成人在线观看视频| 国产精品自在自线| 精品少妇一区二区三区在线| 超碰在线97免费| 5月婷婷6月丁香| 熟妇熟女乱妇乱女网站| 免费日韩中文字幕| 久久久99精品视频| 日本特黄a级片| 妞干网在线观看视频| 中文字幕在线视频一区二区三区| 成年人午夜视频在线观看 | 亚洲美女爱爱视频| 欧美牲交a欧美牲交aⅴ免费真| 青青视频免费在线观看| 五月天激情播播| 日韩大片一区二区| 成人免费观看视频在线观看| a级黄色片免费| 久久最新免费视频| 欧美一级特黄aaa| www.色就是色| 婷婷丁香激情网| 国内自拍视频一区| 日本久久精品一区二区| 日本男人操女人| 无码内射中文字幕岛国片|