要使用多列索引(聯合索引),須要知足最左原則,where條件必須和索引的順序一致,若是隻用到單列則必須是最左列。只有當索引的列順序和ORDER BY子句的順序徹底一致,而且全部列的排序方向(倒序或正序)都同樣時,MySQL纔可以使用索引來對結果作排序。若是查詢須要關聯多張表,則只有當ORDER BY子句引用的字段所有爲第一個表時,才能使用索引作排序。也須要知足索引的最左前綴要求(例外:前導列爲常量的時候)。--摘自《高性能MySQL》
建以下表測試索引排序(版本5.7.17),聯合索引:test_realname_sex_age_index,單列索引:sex_index、age_index,(
一次查詢只能利用一個索引)
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`realname` varchar(10) NOT NULL DEFAULT '',
`sex` tinyint(4) NOT NULL DEFAULT '0',
`age` tinyint(4) NOT NULL DEFAULT '0',
`job` varchar(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `test_realname_sex_age_index` (`realname`,`sex`,`age`),
KEY `sex_index` (`sex`),
KEY `age_index` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
聯合索引測試
使用兩種不一樣的排序方向排序
能利用索引排序
EXPLAIN SELECT * FROM test WHERE realname = 'wen' ORDER BY sex DESC ,age DESC;
不能利用聯合索引排序,由於sex和age的排序方向不一致
EXPLAIN SELECT * FROM test WHERE realname = 'wen' ORDER BY sex DESC ,age ASC ;
用了一個不在索引中的列
EXPLAIN SELECT * FROM test WHERE realname = 'wen' ORDER BY sex,job;
where order by中的列沒法組合成索引的最左前綴
EXPLAIN SELECT * FROM test WHERE realname = 'wen' ORDER BY age;
EXPLAIN SELECT * FROM test WHERE realname = 'wen' ORDER BY sex;
- 查詢在索引第一列上是範圍條件
EXPLAIN SELECT * FROM test WHERE realname > 'wen' ORDER BY sex,age;
EXPLAIN SELECT * FROM test WHERE realname BETWEEN 'wen1' AND 'wen2' ORDER BY sex,age;
索引上有多個等於條件(in)
EXPLAIN SELECT * FROM test WHERE realname = 'wen' AND sex IN (1,2) ORDER BY age;
前導列不爲常量,而且使用範圍條件
不能
EXPLAIN SELECT * FROM test WHERE realname > 'qqq' ORDER BY sex;
能,知足最左原則
EXPLAIN SELECT * FROM test WHERE realname = 'qqq' ORDER BY sex;
通常來講:將選擇性最高的列放到索引的最前列。計算方法
SELECT count(DISTINCT realname)/COUNT(*) realname_selectivity,count(DISTINCT sex)/COUNT(*) sex_selectivity,count(DISTINCT age)/COUNT(*) age_selectivity,count(*) total FROM test;
使用單索引排序的例子
where條件和排序的列不一致
不能使用索引排序
EXPLAIN SELECT * FROM test WHERE sex = 1 ORDER BY age;
使用了範圍
EXPLAIN SELECT * FROM test WHERE age > 17 ORDER BY age;
沒有where條件直接排序
主鍵能夠排序
EXPLAIN SELECT * FROM test ORDER BY id;
不能
EXPLAIN SELECT * FROM test ORDER BY sex;