Innodb關於ORDER BY使用索引的性能問題

如何提升 ORDER BY 查詢速度

通常ORDER BY(對某些列進行排序)語句的性能方面對新人來說很容易被忽略。當然儘管對ORDER BY 的列加索引也不一定能夠對性能有所提升!

關於ORDER BY是對我們查詢出來的記錄按照某種規則進行排序(也就是排序算法)。
如果查詢出來的結果集過大的話,將無法再內存中直接進行排序,可能要藉助磁盤空間來暫時存儲中間結果(凡是跟磁盤掛鉤的,速度肯定不會快到哪裏去),最後才返回給客戶端顯示。

通常情況下如果遇到數據量大的時候使用ORDER BY我們可以考慮給ORDER BY的這些列建立一個索引。(但這可能起不到作用,主要看語法,後面說。)

CREATE TABLE player_score (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
type int(11) NOT NULL DEFAULT ‘0’,
score int(11) unsigned NOT NULL DEFAULT ‘0’,
rank int(11) unsigned NOT NULL DEFAULT ‘0’,
other int(11) unsigned NOT NULL DEFAULT ‘0’,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

例:我們有一個sql語句如下

SELECT * FROM player_score order by type, score LIMIT 10;

對於這條SQL查詢出來的結果集來說,Innodb是先對type類型的值進行排序,如果type值相同再對score進行排序的。
這個步驟有沒覺得似曾相識?

是的!他跟我們的索引邏輯是一樣的

在我們對type跟score建立索引後(順序一定要對!!!先type後score,跟語句中一樣!!!),並命名爲:idx_type_score,這棵B+樹是按照type大小排序,相同則按照score排序,完全符合ORDER BY的需求,對建立了索引的字段進行ORDER BY相當於不需要再次進行各種排序了,也不用考慮排序過程中數據量是否過大,是否會在硬盤中暫存,可以直接從索引中取出對應的值,再進行回表操作就可以取出完整數據了。

PS : 回表其實就是自己建立的非聚簇索引中獲取對應的主鍵值,再回到Innodb爲我們自動建立的聚簇索引中通過主鍵來獲取完整的記錄。
這種操作主要是爲了節省空間,不需要每建立一個索引就保存一套完整的數據。

從上面內容引出如下

我們將SQL語句改成這樣:

SELECT * FROM player_score order by type, score;

可以看出我們相比前面的SQL少了LIMIT 10

二級索引中獲取的每一個主鍵都需要回調聚簇索引中查詢一遍獲取完整數據,所以LIMIT很大的時候其實使用索引反而變成了一種累贅!

因爲沒有了限制,那輸出的數據會隨着表中數據量的變化而變慢(因爲要回表的數據越來越多了),直到最後由查詢優化器去決定使用全表查詢還是索引查詢了。

對於這種情況,使用索引可能並不能提升速度!

進一步改寫SQL語句

從上面的SQL語句可以看出,對於數據量大的情況下上面語句建立索引其實並不能起到預期的效果。
我們可以結合自身的需求,是否能將上面的SQL語句改寫成如下形式:

SELECT type, score, rank FROM player_score order by type, score;

我們只需要查詢type、score、rank三個字段,那在SELECT的時候只查詢出需要的這幾個字段(當然其他情況其實也是不太推薦使用 * 把所有數據查詢出來的),對於這三個字段,我們可以選擇使用覆蓋索引,將type、score、rank建立爲一個索引 idx_type_score_rank
idx_type_score_rank索引的目錄項中一個目錄頁的數據包含以下幾個參數

目錄頁
type
score
rank
id

這是我們再次使用ORDER BY來對type, score進行排序時可以使用idx_type_score_rank索引來進行查找數據(這是聯合索引的特性,不瞭解可以去看看),而且從上面的目錄頁中可以看出,這棵二級索引中包含了我們想要查找的所有數據,所以就不需要再次通過獲取ID後回表來查詢聚簇索引數據。

使用覆蓋索引能夠很好的提升我們的性能,可以很好的避免回表造成的性能損耗。

其他情況

SELECT * FROM player_score order by type ASC, score DESC LIMIT 10;

對type進行升序排序,而對score進行降序排序,對於這種形式Innodb中並不提供索引使用!!!因爲這種要達到排序的目的是需要摻雜是否從左到右還是從右到左的算法。這時使用索引可能就體現的稍微有些累贅。而使用全表查詢可能來的更快些。

默認都是ASC,只要都使用升序或者降序的話是可以使用索引的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章