博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于索引
阅读量:6737 次
发布时间:2019-06-25

本文共 15015 字,大约阅读时间需要 50 分钟。

一.测试数据

MyISAM:

CREATE TABLE `test` (  `id` int(10) NOT NULL AUTO_INCREMENT,  `uid` int(11) NOT NULL,  `name` char(255) CHARACTER SET gbk NOT NULL,  `time` int(11) DEFAULT NULL,  PRIMARY KEY (`id`),  KEY `uid` (`uid`) USING BTREE,  KEY `name_time` (`name`,`time`)) ENGINE=MyISAM;

  

INSERT INTO test VALUES ('1', '14', 'test', '1513338971');INSERT INTO test VALUES ('2', '15', 'jack', '1513338980');INSERT INTO test VALUES ('3', '16', 'home2', '1513338980');

  

InnoDB:

CREATE TABLE `test2` (  `id` int(10) NOT NULL AUTO_INCREMENT,  `uid` int(11) NOT NULL,  `name` char(255) CHARACTER SET gbk NOT NULL,  `time` int(11) DEFAULT NULL,  PRIMARY KEY (`id`),  KEY `uid` (`uid`) USING BTREE,  KEY `name_time` (`name`,`time`)) ENGINE=InnoDB

  

INSERT INTO test2 VALUES ('1', '14', 'test', '1513338971');INSERT INTO test2 VALUES ('2', '15', 'jack', '1513338980');INSERT INTO test2 VALUES ('3', '16', 'home2', '1513338980');

  

 

二.实例分析,只有where的情形下

 1.为什么要有最左前缀限制?

对于多列索引,最左前缀是必须的.否者mysql无法使用索引,因为符合索引是按第一列,第二列,第三列...一次来排序的.不符合最左前缀原则,mysql将放弃使用索引.

如:

mysql> explain select * from test where time=1513338971;+----+-------------+-------+------+---------------+------+---------+------+------+-------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+|  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

 

mysql> explain select * from test2 where time=1513338971;+----+-------------+-------+------+---------------+------+---------+------+------+-------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+|  1 | SIMPLE      | test2 | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

  

2.AND

对于where中的and,只要and两边有一边的字段有索引,就能用到索引.

mysql> explain select * from test where time=1513338971 and name='jack';+----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+| id | select_type | table | type | possible_keys | key       | key_len | ref         | rows | Extra       |+----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+|  1 | SIMPLE      | test  | ref  | name_time     | name_time | 515     | const,const |    1 | Using where |+----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+1 row in set (0.00 sec)mysql> explain select * from test2 where time=1513338971 and name='jack';+----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+| id | select_type | table | type | possible_keys | key       | key_len | ref         | rows | Extra       |+----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+|  1 | SIMPLE      | test2 | ref  | name_time     | name_time | 515     | const,const |    1 | Using where |+----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+1 row in set (0.00 sec)

  

3.OR

对于OR,只要有一个字段没有索引,就不会用到索引

mysql> explain select * from test where  name='jack' or time=1513338971;+----+-------------+-------+------+---------------+------+---------+------+------+-------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+|  1 | SIMPLE      | test  | ALL  | name_time     | NULL | NULL    | NULL |    3 | Using where |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+1 row in set (0.00 sec)mysql> explain select * from test2 where  name='jack' or time=1513338971;+----+-------------+-------+------+---------------+------+---------+------+------+-------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+|  1 | SIMPLE      | test2 | ALL  | name_time     | NULL | NULL    | NULL |    3 | Using where |+----+-------------+-------+------+---------------+------+---------+------+------+-------------+1 row in set (0.00 sec)

  

 

三.Order(不带where条件)

(一).单列索引

1.除非强制走索引或覆盖索引,否者myisam不会用到索引,而进行额外排序(Extra列中出现using filesort)

mysql> explain select * from test order by id desc;+----+-------------+-------+------+---------------+------+---------+------+------+----------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+|  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

myisam是非聚集索引,优化器认为排序完后还需要具体的去读取数据行,所以干脆放弃了使用索引,也就无法索引扫描排序.除非是覆盖索引,否则优化器都不会用到索引,而进行额外排序.

 

2.InnoDB则可以用到索引,只扫描索引就可以排序(type列出现index,表明使用了索引排序)

mysql> explain select * from test2 order by id desc;+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra |+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+|  1 | SIMPLE      | test2 | index | NULL          | PRIMARY | 4       | NULL |    3 |       |+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+

因为是聚集索引,索引和数据是在一起的,优化器认为不必再去查找数据.所以会用到主键索引. 

 

(二).复合索引 

1.覆盖索引情况下,只要排序字段中排序方向一致,两者均可用到索引扫描排序.反向不一致,就不会用到索引排序.

mysql> explain select name,time from test order by name asc,time asc;+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra       |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+|  1 | SIMPLE      | test  | index | NULL          | name_time | 515     | NULL |    3 | Using index |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+

  

mysql> explain select name,time from test2 order by name asc,time asc;+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra       |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+|  1 | SIMPLE      | test2 | index | NULL          | name_time | 515     | NULL |    3 | Using index |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+

  

2.非覆盖索引情况下,即便方向一致,两者均需要去进行额外排序,而且优化器对两者均不进行任何索引优化

mysql> explain select * from test order by name asc,time asc;+----+-------------+-------+------+---------------+------+---------+------+------+----------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+|  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

  

mysql> explain select * from test2 order by name asc,time asc;+----+-------------+-------+------+---------------+------+---------+------+------+----------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+|  1 | SIMPLE      | test2 | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

  

可以强制让其走索引

mysql> explain select * from test force index(name_time) order by name asc,time asc;+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+|  1 | SIMPLE      | test  | index | NULL          | name_time | 515     | NULL |    3 |       |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+mysql> explain select * from test2 force index(name_time) order by name asc,time asc;+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+|  1 | SIMPLE      | test2 | index | NULL          | name_time | 515     | NULL |    3 |       |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+

  

方向不一致就不用去说了.无论如何都会进行一次额外排序的.

 

四.Where+Order

(一).单列索引

1.只要where中有单列索引,一定会用到索引的.

mysql> explain select * from test where uid=14 order by id desc;+----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                       |+----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+|  1 | SIMPLE      | test  | ref  | uid           | uid  | 4       | const |    1 | Using where; Using filesort |+----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+1 row in set (0.00 sec)mysql> explain select * from test2 where uid=14 order by id desc;+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra       |+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+|  1 | SIMPLE      | test2 | ref  | uid           | uid  | 4       | const |    1 | Using where |+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+1 row in set (0.00 sec)

  

但是不同之处在于,myisam的非聚集索引,在排序时还需要数据行取数据,所以会用到额外排序.而innodb因为聚集索引,所以不会进行额外排序.(索引肯定是排好序的)

2.where中没有索引,order中有索引,也不会走索引

mysql> explain select * from test where time=14 order by uid desc;+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                       |+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+|  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where; Using filesort |+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+1 row in set (0.00 sec)mysql> explain select * from test2 where time=14 order by uid desc;+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                       |+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+|  1 | SIMPLE      | test2 | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where; Using filesort |+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+1 row in set (0.00 sec)

 

where中没有索引,order中有索引,也不会走索引 

(二).复合索引

仅讨论where列和order列构建的复合索引

mysql> explain select * from test where name='jack' order by time asc;+----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+| id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra       |+----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+|  1 | SIMPLE      | test  | ref  | name_time     | name_time | 510     | const |    1 | Using where |+----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+1 row in set (0.00 sec)mysql> explain select * from test2 where name='jack' order by time asc;+----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+| id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra       |+----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+|  1 | SIMPLE      | test2 | ref  | name_time     | name_time | 510     | const |    1 | Using where |+----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+1 row in set (0.00 sec)

  

只有where列是一个常量,才使用索引扫描.否则将是额外排序.

mysql> explain select * from test where name>'jack' order by time asc;+----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra                       |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+|  1 | SIMPLE      | test  | range | name_time     | name_time | 510     | NULL |    2 | Using where; Using filesort |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+1 row in set (0.00 sec)mysql> explain select * from test2 where name>'jack' order by time asc;+----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra                       |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+|  1 | SIMPLE      | test2 | range | name_time     | name_time | 510     | NULL |    1 | Using where; Using filesort |+----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+1 row in set (0.00 sec)

  

 

mysql每次只能使用一个索引,无论是单例索引还是符合索引.

只有用到索引,才有可能用到索引扫描(一句废话)

 

 

 

转载于:https://www.cnblogs.com/itfenqing/p/8056752.html

你可能感兴趣的文章
SQL Server 字符串处理函数
查看>>
恢复系统管理员密码的五大奇招
查看>>
英语形容“漂亮女孩”知多少
查看>>
GridView 获取当前行的索引值
查看>>
PHPCMS V9二次开发:内容模块PC标签调用详解
查看>>
tomcat发布web项目,支持域名
查看>>
js和Jquery获取选中select值和文本
查看>>
Linux系统排查1——内存篇
查看>>
Java实现注册邮箱激活验证
查看>>
数据库缓存
查看>>
mvc 数据验证金钱格式decimal格式验证
查看>>
常用的Web服务器
查看>>
UPW学习资料整理 .NET C# 转
查看>>
Oracle12c中新建用户
查看>>
分布式编译工具
查看>>
对我而言晦涩的递归
查看>>
React Native 从入门到原理
查看>>
iOS如何随意的穿插跳跃,push来pop去
查看>>
使用maven编译Java项目 http://www.tuicool.com/articles/YfIfIrq
查看>>
【原创】JDK动态代理,此次之后,永生难忘。
查看>>