在實際的業務中我們經常會用到排序的場景。但是很多時候用了排序之後,效率就會降低很多。
首先說下Mysql
的排序方式,在我所知的是有兩種:
- 一種是排序的字段是有索引的,因爲索引是有序的,所以不需要另外排序,
- 另一種是排序的字段沒有索引,所以需要對結果進行排序,這種情形下如果我們
EXPLAIN
分析的話就會出現Extra: Using filesort
如果用到的了using filesort
對結果進行排序會使效率很大程度上的受影響。所以我們儘量使排序能用到索引。那麼什麼時候才能使用到索引呢,下面舉幾個簡單的例子。有表結構如下:
CREATE TABLE `student` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(20) NOT NULL,
`last_name` varchar(20) NOT NULL,
`created_at` date NOT NULL,
`score` int(3) NOT NULL DEFAULT '0',
`updated_at` timestamp NOT NULL,
PRIMARY KEY (`id`),
KEY `time_sorce_name` (`created_at`,`score`,`first_name`)
) ENGINE=InnoDB AUTO_INCREMENT=6811477 DEFAULT CHARSET=utf8
可以看到這個表中已經有6811477
條數據了。
下面我們來看一些查詢:SELECT * FROM student WHERE created_at='2019-07-10' ORDER BY score;
WHEREcreated_at
條件跟排序字段score
組成了一個符合最左索引條件的組合,所以是可以用到索引的。
但是如果我們把上面的查詢改一下。SELECT * FROM student WHERE created_at='2019-07-10' ORDER BY score,first_name;
這個索引也是可以引用索引排序的。
下面是一些不能使用索引排序的例子:SELECT * FROM student WHERE created_at<'2019-07-10' ORDER BY score;
那麼這個情況是不能使用到索引的,因爲查詢的一個列是一個範圍查詢,所以能用到的索引列也就只有第一列,而排序中的score
列是不能使用到索引的。
下面這個查詢也是不能使用到索引排序的,因爲排序字段中引用了一個不在索引中的列SELECT * FROM student WHERE created_at<'2019-07-10' ORDER BY score,last_name;
下面這個查詢也是不能使用到索引排序的,因爲排序字段中引用了一個不在索引中的列SELECT * FROM student WHERE created_at<'2019-07-10' ORDER BY score,last_name;
下面這個查詢也是不能使用到索引排序的,因爲排序字段跟查詢條件不能組成符合索引的最左條件SELECT * FROM student WHERE created_at<'2019-07-10' ORDER BY first_name;
下面這個查詢也是不能使用到索引排序的,因爲用到IN
查詢也是一個範圍查詢SELECT * FROM student WHERE created_at<'2019-07-10' and score IN(20,80) ORDER BY first_name;
這些只是一些簡單的示例,在實際場景中業務會更復雜,也會存在多張表的時候。這個時候就需要我們實際去分析問題了。只要是知道了基本原理,其他的都是順藤摸瓜。