mysql的orderby是如何工作的

2021-10-09 20:29:18 字數 2067 閱讀 1113

1.建表語句

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;

2.假設裡面插入很多資料,現在需要查詢

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

3.分析2的查詢

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

using index condition,表示雖然觸發了city的索引,但是因為沒有索引覆蓋,所以還必須通過主鍵id回表查詢其他字段,

using filesort 表示使用排序,mysql會通過設定的sort_buff大小給每個執行緒在記憶體裡進行排序

這裡解釋這段sql是如何執行的:

1.在sort_buff裡生成列city,name,age

2.通過city索引找到主鍵id,在通過id回表查詢獲取name,age,填入記錄

3.在進行下乙個city的索引的主鍵id,在回表查詢填入記錄

4.重複3步驟,直到查詢條件不滿足時,退出

5.在sort_buff中按照name進行快速排序

6.返回結果集

這種排序方式成為全欄位排序,這裡還存在乙個問題,就是在sort_buff裡排序的時候,如果當我們的資料量時大於sort_buffer_size設定的引數時,那麼我們就沒辦法一次性在記憶體裡進行排序完成,只能借助磁碟來輔助排序了。mysql通過生成臨時檔案,然後在合併臨時檔案的方式來進行輔助排序。

mysql還在另一種排序方式:rowid排序。

這種排序是指當我們設定了set max_length_for_sort_data = 16引數時,即排序的資料裡每一行的大小不能超過16b,如果超過了,比如上面我們的按照name排序,sort_buff裡存的每一行記錄時name,city,age。三個欄位的大小已經超過16b了。所以這裡必須更換排序演算法:

1.在sort_buff記憶體了生成name,id兩列

2.從索引city查詢到主鍵id,然後回表獲取name,id的值填入記錄

3.下一條記錄重複2操作,直到不滿足條件為止

4.在sort_buff裡按照name快速排序

5.在通過id,進行主鍵回表操作,獲取name,age欄位

6.返回結果集

如圖:

通過rowid排序,可以明顯的發現又多了一次回表的操作,所以mysql在萬不得已的情況下不會優先考慮這種排序演算法的,

這裡可以看出mysql的優化理論:在sort_buff足夠的條件下,通過記憶體直接排序,減少磁碟的io!

那麼這裡假設我們不在程式裡進行排序,那麼如何讓mysql幫我直接排序,而不使用上面那種排序演算法呢?

還記得以前提到過的索引覆蓋的理論嘛?當索引覆蓋時,我們查詢的時候就不需要回表了,而且索引都是拍好序的資料是可以直接返回的

那麼這裡我們直接將city,name,age設定位聚合索引,此時查詢觸發索引覆蓋即可快速返回結果了

這裡的using index 就是表示索引覆蓋了,所以我們沒有看到前面的using filesort!

「orderby」是怎麼工作的

假設你要查詢城市是 杭州 的所有人名字,並且按照姓名排序返回前1000個人的姓名 年齡。假設這個表的部分定義是這樣的 create table t id int 11 notnull city varchar 16 not null name varchar 16 not null age int ...

mysql的order by導致很慢

mysql的order by導致很慢 解決方法 我解決的方法是使用force index強制使用索引,為tcug datetime欄位新建乙個名字為tcug datetime的索引 normal btree selecta.tcug datetime from manage.tb crm files...

MySQL如何優化ORDER BY

某些情況中,mysql可以使用乙個索引來滿足order by子句,而不需要額外的排序。即使order by不確切匹配索引,只要where子句中的所有未使用的索引部分和所有額外的order by 列為常數,就可以使用索引。下面的查詢使用索引來解決order by部分 某些情況中,mysql可以使用乙個...