溫馨提示×

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

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

(轉(zhuǎn))MySQL ORDER BY 的實(shí)現(xiàn)分析

發(fā)布時(shí)間:2020-08-11 14:25:05 來(lái)源:ITPUB博客 閱讀:141 作者:denniswwh 欄目:MySQL數(shù)據(jù)庫(kù)
作者:Sky.Jian | 可以任意轉(zhuǎn)載, 但轉(zhuǎn)載時(shí)務(wù)必以超鏈接形式標(biāo)明文章原始出處 和 作者信息 及 版權(quán)聲明
鏈接:http://www.jianzhaoyang.com/database/mysql_order_by_implement

總的來(lái)說,在 MySQL 中的ORDER BY有兩種排序?qū)崿F(xiàn)方式,一種是利用有序索引獲取有序數(shù)據(jù),另一種則是通過相應(yīng)的排序算法,將取得的數(shù)據(jù)在內(nèi)存中進(jìn)行排序。

下面將通過實(shí)例分析兩種排序?qū)崿F(xiàn)方式及實(shí)現(xiàn)圖解:
假設(shè)有 Table A 和 B 兩個(gè)表結(jié)構(gòu)分別如下:

[@more@]
sky@localhost : example01:48:21; showcreatetableAG
***************************
1.row **************************
Table: A
CreateTable: CREATETABLE`A`(
`c1`int(11)NOTNULLdefault'0',
`c2`char(2)defaultNULL,
`c3`varchar(16)defaultNULL,
`c4`datetimedefaultNULL,
PRIMARYKEY (`c1`))ENGINE=MyISAMDEFAULTCHARSET=utf8

sky@localhost : example01:48:32; showcreatetableBG
***************************
1.row***************************
Table: B
CreateTable: CREATETABLE`B`(
`c1`int(11)NOTNULLdefault'0',
`c2`char(2)defaultNULL,
`c3`varchar(16)defaultNULL,
PRIMARYKEY (`c1`),
KEY`B_c2_ind`(`c2`))ENGINE=MyISAMDEFAULTCHARSET=utf8

1、利用有序索引進(jìn)行排序,實(shí)際上就是當(dāng)我們 Query 的 ORDER BY 條件和 Query 的執(zhí)行計(jì)劃中所利用的 Index 的索引鍵(或前面幾個(gè)索引鍵)完全一致,且索引訪問方式為 rang、 ref 或者 index 的時(shí)候,MySQL 可以利用索引順序而直接取得已經(jīng)排好序的數(shù)據(jù)。這種方式的 ORDER BY 基本上可以說是最優(yōu)的排序方式了,因?yàn)?MySQL 不需要進(jìn)行實(shí)際的排序操作。

假設(shè)我們?cè)赥able A 和 B 上執(zhí)行如下SQL:

sky@localhost : example01:44:28; EXPLAINSELECTA.* FROMA,BWHEREA.c12ANDA.c25ANDA.c2 = B.c2ORDERBYA.c1G
***************************
1.row**************************
id: 1
select_type: SIMPLE
table: A
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 3
Extra: Usingwhere
***************************
2.row***************************
id: 1
select_type: SIMPLE
table: B
type: ref
possible_keys: B_c2_ind
key: B_c2_ind
key_len: 7
ref: example.A.c2
rows: 2
Extra: Usingwhere; Usingindex

我們通過執(zhí)行計(jì)劃可以看出,MySQL實(shí)際上并沒有進(jìn)行實(shí)際的排序操作,實(shí)際上其整個(gè)執(zhí)行過程如下圖所示:

(轉(zhuǎn))MySQL ORDER BY 的實(shí)現(xiàn)分析

2、通過相應(yīng)的排序算法,將取得的數(shù)據(jù)在內(nèi)存中進(jìn)行排序方式,MySQL 比需要將數(shù)據(jù)在內(nèi)存中進(jìn)行排序,所使用的內(nèi)存區(qū)域也就是我們通過 sort_buffer_size 系統(tǒng)變量所設(shè)置的排序區(qū)。這個(gè)排序區(qū)是每個(gè) Thread 獨(dú)享的,所以說可能在同一時(shí)刻在 MySQL 中可能存在多個(gè) sort buffer 內(nèi)存區(qū)域。

第二種方式在 MySQL Query Optimizer 所給出的執(zhí)行計(jì)劃(通過 EXPLAIN 命令查看)中被稱為 filesort。在這種方式中,主要是由于沒有可以利用的有序索引取得有序的數(shù)據(jù),MySQL只能通過將取得的數(shù)據(jù)在內(nèi)存中進(jìn)行排序然后再將數(shù)據(jù)返回給 客戶端。在 MySQL 中 filesort 的實(shí)現(xiàn)算法實(shí)際上是有兩種的,一種是首先根據(jù)相應(yīng)的條件取出相應(yīng)的排序字段和可以直接定位行數(shù)據(jù)的行指針信息,然后在 sort buffer 中進(jìn)行排序。另外一種是一次性取出滿足條件行的所有字段,然后在 sort buffer 中進(jìn)行排序。

在 MySQL4.1 版本之前只有第一種排序算法,第二種算法是從 MySQL4.1開始的改進(jìn)算法,主要目的是為了減少第一次算法中需要兩次訪問表數(shù)據(jù)的 IO 操作,將兩次變成了一次,但相應(yīng)也會(huì)耗用更多的 sort buffer 空間。當(dāng)然,MySQL4.1開始的以后所有版本同時(shí)也支持第一種算法,MySQL 主要通過比較我們所設(shè)定的系統(tǒng)參數(shù) max_length_for_sort_data 的大小和 Query 語(yǔ)句所取出的字段類型大小總和來(lái)判定需要使用哪一種排序算法。如果 max_length_for_sort_data 更大,則使用第二種優(yōu)化后的算法,反之使用第一種算法。所以如果希望 ORDER BY 操作的效率盡可能的高,一定要主義 max_length_for_sort_data 參數(shù)的設(shè)置。曾經(jīng)就有同事的數(shù)據(jù)庫(kù)出現(xiàn)大量的排序等待,造成系統(tǒng)負(fù)載很高,而且響應(yīng)時(shí)間變得很長(zhǎng),最后查出正是因?yàn)?MySQL 使用了傳統(tǒng)的第一種排序算法而導(dǎo)致,在加大了 max_length_for_sort_data 參數(shù)值之后,系統(tǒng)負(fù)載馬上得到了大的緩解,響應(yīng)也快了很多。

我們?cè)倏纯?MySQL 需要使用 filesort 實(shí)現(xiàn)排序的實(shí)例。

假設(shè)我們改變一下我們的 Query,換成通過A.c2來(lái)排序,再看看情況:

sky@localhost : example01:54:23; EXPLAINSELECTA.* FROMA,BWHEREA.c12ANDA.c25ANDA.c2 = B.c2ORDERBYA.c2G
***************************
1.row***************************
id: 1
select_type: SIMPLE
table: A
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 3
Extra: Usingwhere; Usingfilesort
***************************
2.row***************************
id: 1
select_type: SIMPLE
table: B
type: ref
possible_keys: B_c2_ind
key: B_c2_ind
key_len: 7
ref: example.A.c2
rows: 2
Extra: Usingwhere; Usingindex

MySQL 從 Table A 中取出了符合條件的數(shù)據(jù),由于取得的數(shù)據(jù)并不滿足 ORDER BY 條件,所以 MySQL 進(jìn)行了 filesort 操作,其整個(gè)執(zhí)行過程如下圖所示:

(轉(zhuǎn))MySQL ORDER BY 的實(shí)現(xiàn)分析

在 MySQL 中,filesort 操作還有一個(gè)比較奇怪的限制,那就是其數(shù)據(jù)源必須是來(lái)源于一個(gè) Table,所以,如果我們的排序數(shù)據(jù)如果是兩個(gè)(或者更多個(gè)) Table 通過 Join所得出的,那么 MySQL 必須通過先創(chuàng)建一個(gè)臨時(shí)表(Temporary Table),然后再將此臨時(shí)表的數(shù)據(jù)進(jìn)行排序,如下例所示:

sky@localhost : example02:46:15; explainselectA.* fromA,BwhereA.c12andA.c25andA.c2 = B.c2orderbyB.c3G
***************************
1.row***************************
id: 1
select_type: SIMPLE
table: A
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 3
Extra: Usingwhere; Usingtemporary; Usingfilesort
***************************
2.row***************************
id: 1
select_type: SIMPLE
table: B
type: ref
possible_keys: B_c2_ind
key: B_c2_ind
key_len: 7
ref: example.A.c2
rows: 2
Extra: Usingwhere

這個(gè)執(zhí)行計(jì)劃的輸出還是有點(diǎn)奇怪的,不知道為什么,MySQL Query Optimizer 將 “Using temporary” 過程顯示在第一行對(duì) Table A 的操作中,難道只是為讓執(zhí)行計(jì)劃的輸出少一行?

實(shí)際執(zhí)行過程應(yīng)該是如下圖所示:
(轉(zhuǎn))MySQL ORDER BY 的實(shí)現(xiàn)分析

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

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

AI