溫馨提示×

溫馨提示×

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

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

ORDER BY分類

發(fā)布時(shí)間:2020-07-03 09:18:02 來源:網(wǎng)絡(luò) 閱讀:1242 作者:DBAspace 欄目:MySQL數(shù)據(jù)庫

前言

排序是數(shù)據(jù)庫中的一個(gè)基本功能,MySQL也不例外。通過Order by語句即能達(dá)到將指定的結(jié)果集排序的目的,

其實(shí)不僅僅是Order by語句,Group by語句,Distinct語句都會(huì)隱含使用排序

在實(shí)際業(yè)務(wù)場景中,一些開發(fā)的大牛動(dòng)不動(dòng)來個(gè)orderby,SQL看起寫的非常溜,而實(shí)際業(yè)務(wù)應(yīng)用導(dǎo)致GAME OVER......

首先介紹MySQL實(shí)現(xiàn)排序的內(nèi)部原理,并介紹與排序相關(guān)的參數(shù),最后結(jié)合實(shí)際給出幾個(gè)"奇怪"排序,來談?wù)勁判蛞恢聠栴}

1、排序?qū)崿F(xiàn)的算法:

對于不能利用索引避免排序的 SQL,數(shù)據(jù)庫不得不自己排序功能以滿足業(yè)務(wù)需求,執(zhí)行計(jì)劃中會(huì)出現(xiàn)"USING TEMPORARY; USING filesort",

有時(shí)候filesore并不意味著就是文件排序也有可能是內(nèi)存排序,只有由參數(shù)sort_buffer_size和結(jié)果集大小確定。

MySQL內(nèi)部排序主要有3種方式:常規(guī)排序、優(yōu)化排序和優(yōu)先隊(duì)列排序,假設(shè)表結(jié)構(gòu)如下:

CREATE TABLE `t1` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `col1` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,

  `col2` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,

  `col3` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `col1` (`col1`,`col2`)

) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

SELECT col1,col2,col3 FROM t1 WHERE col1="100" ORDER BY col2;

    a.常規(guī)排序

(1).從表t1中獲取滿足WHERE條件的記錄

(2).對于每條記錄,將記錄的主鍵+排序鍵(id,col2)取出放入sort buffer

(3).如果sort buffer可以存放所有滿足條件的(id,col2)對,則進(jìn)行排序;否則sort buffer滿后,進(jìn)行排序并固化到臨時(shí)文件中。(排序算法采用的是快速排序算法)

(4).若排序中產(chǎn)生了臨時(shí)文件,需要利用歸并排序算法,保證臨時(shí)文件中記錄是有序的

(5).循環(huán)執(zhí)行上述過程,直到所有滿足條件的記錄全部參與排序

(6).掃描排好序的(id,col2)對,并利用id去撈取SELECT需要返回的列(col1,col2,col3)

(7).將獲取的結(jié)果集返回

從上述流程來看,是否使用文件排序主要看sort buffer是否能容下需要排序的(id,col2)對,這個(gè)buffer的大小由sort_buffer_size參數(shù)控制。此外一次排序需要兩次IO,一次是撈(id,col2),第二次是撈(col1,col2,col3),由于返回的結(jié)果集是按col2排序,因此id是亂序的,通過亂序的id去撈(col1,col2,col3)時(shí)會(huì)產(chǎn)生大量的隨機(jī)IO。對于第二次MySQL本身一個(gè)優(yōu)化,

即在撈之前首先將id排序,并放入緩沖區(qū),這個(gè)緩存區(qū)大小由參數(shù)read_rnd_buffer_size控制,然后有序去撈記錄,將隨機(jī)IO轉(zhuǎn)為順序IO

    b.優(yōu)化排序

常規(guī)排序方式除了排序本身,還需要額外兩次IO。優(yōu)化的排序方式相對于常規(guī)排序,減少了第二次IO。主要區(qū)別在于,放入sort buffer不是(id,col2),而是(col1,col2,col3)。由于sort buffer中包含了查詢需要的所有字段,因此排序完成后可以直接返回,無需二次撈數(shù)據(jù)。這種方式的代價(jià)在于,同樣大小的sort buffer,能存放的(col1,col2,col3)數(shù)目要小于(id,col2),如果sort buffer不夠大,可能導(dǎo)致需要寫臨時(shí)文件,造成額外的IO。當(dāng)然MySQL提供了參數(shù)max_length_for_sort_data,

只有當(dāng)排序元組小于max_length_for_sort_data時(shí),才能利用優(yōu)化排序方式,否則只能用常規(guī)排序方式

    c.優(yōu)先隊(duì)列排序

為了得到最終的排序結(jié)果,無論怎樣,我們都需要將所有滿足條件的記錄進(jìn)行排序才能返回。那么相對于優(yōu)化排序方式,

在空間層面做了優(yōu)化黑盒加入了一種新的排序方式--優(yōu)先隊(duì)列,這種方式采用堆排序?qū)崿F(xiàn),堆排序算法特征正好可以解limit M,N 這類排序的問題,雖然仍然需要所有元素參與排序,但是只需要M+N個(gè)元組的sort buffer空間即可,對于M,N很小的場景,基本不會(huì)因?yàn)閟ort buffer不夠而導(dǎo)致需要臨時(shí)文件進(jìn)行歸并排序的問題。

對于升序,采用大頂堆,最終堆中的元素組成了最小的N個(gè)元素,對于降序,采用小頂堆,最終堆中的元素組成了最大的N的元素


2、排序優(yōu)化與索引使用

為了優(yōu)化SQL語句的排序性能,最好的情況是避免排序,合理利用索引是一個(gè)不錯(cuò)的方法。

因?yàn)樗饕旧硪彩怯行虻模绻谛枰判虻淖侄紊厦娼⒘撕线m的索引,那么就可以跳過排序的過程,提高SQL的查詢速度,\

通過一些典型SQL說明哪些可以利用索引減少排序,哪些不能,

1、select * from t1 order by col1,col2

2、select * from t1 where  col1="100" order by col2

3、select *from t1 col1>"100" order by col1 asc

4、select * from  t1 where col1="100" and col2>"100" order by col2

3、不能利用索引避免排序

通過索引掃描的記錄數(shù)超過30%,變?nèi)頀呙?/p>

聯(lián)合索引中,第一索引列使用范圍查詢

聯(lián)合索引中,第一查詢條件不是最左索引列

升降序不一致無法使用

排序字段在多個(gè)索引中無法使用(一個(gè)聯(lián)合索引一個(gè)單列索引,一條SQL一次只能使用一個(gè)索引)

排序字段是單獨(dú)的列無法使用索引

4、業(yè)務(wù)案例,添加合理的索引

    1、業(yè)務(wù)DDL:

    

ORDER BY分類

ORDER BY分類

    2、對原SQL執(zhí)行計(jì)劃的查看:

    ORDER BY分類

    3、優(yōu)化后的SQL執(zhí)行計(jì)劃-1

    ORDER BY分類

   3、優(yōu)化后的SQL執(zhí)行計(jì)劃-2

    ORDER BY分類

主要對原SQL進(jìn)行改寫以及添加相應(yīng)的索引,即可實(shí)現(xiàn)SQL優(yōu)化,運(yùn)行效率的最優(yōu)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI