MySQL ORDER BY 的實(shí)現(xiàn)分析
下面將通過實(shí)例分析兩種排序?qū)崿F(xiàn)方式及實(shí)現(xiàn)圖解:
假設(shè)有 Table A 和 B 兩個(gè)表結(jié)構(gòu)分別如下:
sky@localhost : example 01:48:21> show create table AG
*************************** 1. row ***************************
Table: A
Create Table: CREATE TABLE `A` (
`c1` int(11) NOT NULL default ‘0′,
`c2` char(2) default NULL,
`c3` varchar(16) default NULL,
`c4` datetime default NULL,
PRIMARY KEY (`c1`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
sky@localhost : example 01:48:32> show create table BG
*************************** 1. row ***************************
Table: B
Create Table: CREATE TABLE `B` (
`c1` int(11) NOT NULL default ‘0′,
`c2` char(2) default NULL,
`c3` varchar(16) default NULL,
PRIMARY KEY (`c1`),
KEY `B_c2_ind` (`c2`)
) ENGINE=MyISAM DEFAULT CHARSET=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 : example 01:44:28> EXPLAIN SELECT A.* FROM A,B
-> WHERE A.c1 > 2 AND A.c2 < 5 AND A.c2 = B.c2 ORDER BY A.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: Using where
*************************** 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: Using where; Using index
我們通過執(zhí)行計(jì)劃可以看出,MySQL實(shí)際上并沒有進(jìn)行實(shí)際的排序操作,實(shí)際上其整個(gè)執(zhí)行過程如下圖所示:
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 語句所取出的字段類型大小總和來判定需要使用哪一種排序算法。如果 max_length_for_sort_data 更大,則使用第二種優(yōu)化后的算法,反之使用第一種算法。所以如果希望 ORDER BY 操作的效率盡可能的高,一定要主義 max_length_for_sort_data 參數(shù)的設(shè)置。曾經(jīng)就有同事的數(shù)據(jù)庫出現(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來排序,再看看情況:
sky@localhost : example 01:54:23> EXPLAIN SELECT A.* FROM A,B
-> WHERE A.c1 > 2 AND A.c2 < 5 AND A.c2 = B.c2 ORDER BY A.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: Using where; Using filesort
*************************** 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: Using where; Using index
MySQL 從 Table A 中取出了符合條件的數(shù)據(jù),由于取得的數(shù)據(jù)并不滿足 ORDER BY 條件,所以 MySQL 進(jìn)行了 filesort 操作,其整個(gè)執(zhí)行過程如下圖所示:
在 MySQL 中,filesort 操作還有一個(gè)比較奇怪的限制,那就是其數(shù)據(jù)源必須是來源于一個(gè) Table,所以,如果我們的排序數(shù)據(jù)如果是兩個(gè)(或者更多個(gè)) Table 通過 Join所得出的,那么 MySQL 必須通過先創(chuàng)建一個(gè)臨時(shí)表(Temporary Table),然后再將此臨時(shí)表的數(shù)據(jù)進(jìn)行排序,如下例所示:
sky@localhost : example 02:46:15> explain select A.* from A,B
-> where A.c1 > 2 and A.c2 < 5 and A.c2 = B.c2 order by B.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: Using where; Using temporary; Using filesort
*************************** 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: Using where
這個(gè)執(zhí)行計(jì)劃的輸出還是有點(diǎn)奇怪的,不知道為什么,MySQL Query Optimizer 將 “Using temporary” 過程顯示在第一行對(duì) Table A 的操作中,難道只是為讓執(zhí)行計(jì)劃的輸出少一行?
實(shí)際執(zhí)行過程應(yīng)該是如下圖所示:
- MySQL Order by 語句用法與優(yōu)化詳解
- 深入解析mysql中order by與group by的順序問題
- MySQL中union和order by同時(shí)使用的實(shí)現(xiàn)方法
- MySQL Order By語法介紹
- MySQL Order By索引優(yōu)化方法
- MySQL order by性能優(yōu)化方法實(shí)例
- MySQL中Order By多字段排序規(guī)則代碼示例
- 詳談mysql order by in 的字符順序(推薦)
- MySQL Order By Rand()效率分析
- MySQL不使用order by實(shí)現(xiàn)排名的三種思路總結(jié)
相關(guān)文章
mysql建庫時(shí)提示Specified key was too long max key length is 1000
本文將詳細(xì)提供mysql建庫時(shí)提示Specified key was too long max key length is 1000 bytes的問題的解決方法,有需求的朋友可以參考2012-11-11mysql 5.7.17 安裝教程 附MySQL服務(wù)無法啟動(dòng)的解決方法
這篇文章主要為大家詳細(xì)介紹了mysql 5.7.17安裝教程,并且為大家分享了MySQL服務(wù)無法啟動(dòng)的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03Mysql升級(jí)到5.7后遇到的group by查詢問題解決
這篇文章主要給大家介紹了關(guān)于Mysql升級(jí)到5.7后遇到的group by查詢問題的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)同樣遇到這個(gè)問題的朋友們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09mysql學(xué)習(xí)筆記之基礎(chǔ)知識(shí)
本文是MySQL學(xué)習(xí)筆記系列文章的第一篇,給大家簡(jiǎn)單講解下MySQL的一些檢查操作命令,希望大家能夠喜歡2017-02-02關(guān)于MySql鏈接url參數(shù)的設(shè)置
最近整理了一下網(wǎng)上關(guān)于MySql 鏈接url 參數(shù)的設(shè)置以及常用的幾個(gè)較為重要的參數(shù),大家若感興趣可以參考下2014-03-03mysql Sort aborted: Out of sort memory, consider increasing
這篇文章主要介紹了mysql Sort aborted: Out of sort memory, consider increasing server sort buffer size的解決方法,需要的朋友可以參考下2016-05-05