order by:
create table test04(
id int primary key auto_increment,
c1 char(10),
c2 char(10),
c3 char(10),
c4 char(10),
c5 char(10)
);
insert into test04(c1,c2,c3,c4,c5)
values
('a1','a2','a3','a4','a5'),
('b1','b2','b3','b4','b5'),
('c1','c2','c3','c4','c5'),
('d1','d2','d3','d4','d5'),
('e1','e2','e3','e4','e5');
建索引:create index inx_1234 on test04(c1,c2,c3,c4);
mysql> explain select * from test04 where c1 = 'a1';
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | test04 | NULL | ref | inx_1234 | inx_1234 | 31 | const | 1 | 100.00 | NULL |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.13 sec)
mysql> explain select * from test04 where c2 = 'a2' and c1 = 'a1' and c4 = 'c4' and c3 = 'c3';
+----+-------------+--------+------------+------+---------------+----------+---------+-------------------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------------------------+------+----------+-------+
| 1 | SIMPLE | test04 | NULL | ref | inx_1234 | inx_1234 | 124 | const,const,const,const | 1 | 100.00 | NULL |
+----+-------------+--------+------------+------+---------------+----------+---------+-------------------------+------+----------+-------+
1 row in set, 1 warning (0.06 sec)
mysql> explain select * from test04 where c2 = 'a2' and c4 = 'c4' and c3 = 'c3';
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | test04 | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from test04 where c1 = 'a1' and c4 = 'c4' and c3 = 'c3';
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-----------------------+
| 1 | SIMPLE | test04 | NULL | ref | inx_1234 | inx_1234 | 31 | const | 1 | 20.00 | Using index condition |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
說明即便是查詢的順序和索引順序不一致,索引也不會失效。但是一旦使用索引時有跨列的行爲,被跨列的後面的複合索引都會失效。
當有範圍查詢時:
mysql> explain select * from test04 where c1 = 'a1' and c2 = 'a2' and c3 > 'a3' and c4 = 'c4';
+----+-------------+--------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | test04 | NULL | range | inx_1234 | inx_1234 | 93 | NULL | 1 | 20.00 | Using index condition |
+----+-------------+--------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
從key看出確實用到了索引,雖然ref是NULL。但是符合範圍之後全失效的原則。
mysql> explain select * from test04 where c1 = 'a1' and c2 = 'a2' and c4 > 'a4' and c3 = 'c3';
+----+-------------+--------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | test04 | NULL | range | inx_1234 | inx_1234 | 124 | NULL | 1 | 100.00 | Using index condition |
+----+-------------+--------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.06 sec)
結合上面的例子可以看出用到了4個索引,從key_len可以看出。
mysql> explain select * from test04 where c1 = 'a1' and c2 = 'a2' and c4 > 'a4' order by c3 ;
+----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-----------------------+
| 1 | SIMPLE | test04 | NULL | ref | inx_1234 | inx_1234 | 62 | const,const | 1 | 33.33 | Using index condition |
+----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-----------------------+
1 row in set, 1 warning (0.05 sec)
用到了兩個索引,從排序的角度理解,c3的也用到了。
mysql> explain select * from test04 where c1 = 'a1' and c2 = 'a2' order by c4 ;
+----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+----------------+
| 1 | SIMPLE | test04 | NULL | ref | inx_1234 | inx_1234 | 62 | const,const | 1 | 100.00 | Using filesort |
+----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)
一定只用到了兩個索引。並且出現了using filesort.
mysql> explain select * from test04 where c1 = 'a1' and c5 = 'a5' order by 'c2,c3';
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | test04 | NULL | ref | inx_1234 | inx_1234 | 31 | const | 1 | 20.00 | Using where |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
用到了一個查找索引,兩個排序索引。c5是干擾項。
mysql 8> explain select * from test04 where c1 = 'a1' and c5 = 'a5' order by 'c3,c2';
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | test04 | NULL | ref | inx_1234 | inx_1234 | 31 | const | 1 | 20.00 | Using where |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
以上兩個例子,第二個在低版本中會出現using filesort.
一般情況下如果order by的順序和複合索引的順序不一致都會出現using filesort,前提是查找列中無排序列。
order by 子句儘量使用index方式排序,避免使用filesort方式排序,且儘可能在索引上完成排序稻作,遵照索引建的最佳左前綴法則。
create table tabA(
age int,
birth timestamp not null
);
insert into tabA(age,birth) values (23,now());
insert into tabA(age,birth) values (24,now());
insert into tabA(age,birth) values (25,now());
insert into tabA(age,birth) values (26,now());
create index idx_a_b on tabA(age,birth);
mysql> explain select * from tabA where age > 20 order by age;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | tabA | NULL | index | idx_a_b | idx_a_b | 9 | NULL | 4 | 100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from tabA where age > 20 order by birth;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
| 1 | SIMPLE | tabA | NULL | index | idx_a_b | idx_a_b | 9 | NULL | 4 | 100.00 | Using where; Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
1 row in set, 1 warning (0.00 sec)
從以上兩個列子可以看出雖然用到了索引,但是如果order by 的順序和索引建的順序不一致的時候會產生using filesort.
mysql> explain select * from tabA order by age asc,birth desc;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------------+
| 1 | SIMPLE | tabA | NULL | index | NULL | idx_a_b | 9 | NULL | 4 | 100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.01 sec)
因爲order by默認升序兩個排序存在衝突,因此會產生using filesort.
此時僅僅依靠索引是無法解決的,需要修改mysql的配置文件的
sort_buffer_size的容量,同時可能也需要改max_length_for_size_data的容量。
group by的優化原則和order by差不多:
(1)分組順序按照複合索引的最佳左前綴原則進行;
(2)當分組時無法直接使用索引時應考慮修改配置文件的sort_buffer_size,max_length_for_size_data
具體修改的大小依照具體情況而定;
(3)having語句基於group by,但是也是用於過濾,因此能在where後直接過濾的儘量不用在使用having;