Mysql索引
当表中的数据量到达几十万甚至上百万的时候,SQL查询所花费的时间会很长,导致业务超时出错,此时就需要用索引来加速SQL查询
。
由于索引也是需要存储成索引文件的,因此对索引的使用也会涉及磁盘I/O操作
。如果索引创建过多,使用不当,会造成SQL查询时,进行大量无用的磁盘I/O操作,降低了SQL的查询效率,适得其反,因此掌握良好的索引创建原则非常重要!
索引分类
索引是创建在表上的,是对数据库表中一列或者多列的值进行排序
的一种结果。索引的核心是提高查询的速度!
,其本质也是一种数据结构。
索引的优点: 提高查询效率
索引的缺点: 索引并非越多越好,他也是需要被存储成为索引文件的
,过多的索引会导致CPU使用率居高不下,由于数据的改变,会造成索引文件的改动,过多的磁盘I/O造成CPU负荷太重
。
分类:
物理上(聚集索引&非聚集索引)
逻辑上(如下:)
- 普通索引:
没有任何限制条件,可以给任何类型的字段创建普通索引
(创建新表&已创建表,数量是不限的,但并不意味着可以一直添加,一张表的一次sql查询只能用一个索引,比如where a=1 and b=‘M’
只能用二者其一的索引) - 唯一性索引:
使用UNIQUE修饰的字段,会自动创建,主键索引就隶属于唯一性索引
- 主键索引:
使用Primary Key修饰的字段会自动创建索引
(MyISAM在没有主键的情况下不会自动添加,InnoDB在没有主键的情况下,会默认添加一个整形列作为主键,因为InnoDB的数据和索引存放在一个文件,必须建立索引树,然后在索引树上存放数据) - 单列索引:在一个字段上创建索引
- 多列索引:在表的多个字段上创建索引 (uid+cid,多列索引必须使用到第一个列,才能用到多列索引,否则索引用不上)
- 全文索引:使用
FULLTEXT
参数可以设置全文索引,只支持CHAR
,VARCHAR
和TEXT
类型的字段上,常用于数据量较大的字符串类型上,可以提高查询速度(线上项目支持专门的搜索功能,给后台服务器增加专门的搜索引擎支持快速高校的搜索elasticsearch 简称es C++开源的搜索引擎 搜狗的workflow)
索引创建和删除
创建表的时候指定索引字段:
CREATE TABLE index1(id INT,
name VARCHAR(20),
sex ENUM('male', 'female'),
INDEX(id,name));#多列索引
查索引名:show create table\G
在已经创建的表上添加索引:
CREATE [UNIQUE] INDEX 索引名 ON 表名(属性名(length) [ASC | DESC]);
删除索引:
DROP INDEX 索引名 ON 表名;
索引优化建议:
- 经常作为
where
条件过滤的字段考虑添加索引
字符串列创建索引
时,尽量规定索引的长度
,能区分即可,而不能让索引值的长度key_len
过长索引字段如果涉及类型强转、mysql函数调用、表达式计算等
,索引就用不上了:(比如你给passwd列设置索引,在where过滤条件中写的是where passwd = 10000;但是其实passwd是varchar类型,这样索引就用不上了,还是会整表搜索,改成where passwd = '10000’后搜索时间明显缩短)
(注意
:面试过程中回答索引优化问题时:结合实际,不要教条主义,要说曾经建立了。。。。表,发现了。。。问题,于是做了。。。优化)
问题: 给字段加索引,将该字段作为过滤条件,在搜索时一定会使用索引吗?
其实不是,mysql也会优化,如果使用索引搜索到的数据占据了所有数据的百分之七八十的时候,这时就不会使用索引,因为此时使用索引,首先需要读取索引文件花费磁盘IO,还要扫描索引树,还不如整表扫描。
总而言之,mysql会比较用或不用的数据量的大小,因为毕竟使用索引的操作步骤还是比较复杂的。
使用explain查看sql的执行计划
使用explain查看sql的执行计划,分析索引的执行过程,mysql的user权限表,示例如下:
mysql> explain select Host,User from user where Host='%'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
partitions: NULL
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 180
ref: const
rows: 1
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.00 sec)
可以看到使用了主键索引,共扫描1行,Using index表示直接从索引树上查询到结果,不需要回表。
mysql> explain select Host,User from user where User='root'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
partitions: NULL
type: index
possible_keys: NULL
key: PRIMARY
key_len: 276
ref: NULL
rows: 4
filtered: 25.00
Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from user where User='root'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
filtered: 25.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)
附录 : explain结果字段分析
1、select_type
simple
:表示不需要union操作或者不包含子查询的简单select语句。有连接查询时,外层的查询为simple且只有一个。primary
:一个需要union操作或者含有子查询的select,位于最外层的单位查询的select_type即为primary且只有一个。union
:union连接的两个select查询,除了第一个表外,第二个以后的表的select_type都是union。union result
:包含union的结果集,在union和union all语句中,因为它不需要参与查询,所以id 字段为null。
2、table
- 显示查询的表名;如果不涉及对数据库操作,这里显示null;
- 如果显示为尖括号就表示这是个临时表,后边的N就是执行计划中的id,表示结果来自于这个查询产生的;
- 如果是尖括号括起来<union M,N>也是一个临时表,表示这个结果来自于union查询的id为M,N 的结果集;
3、type
const
:使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type就是const。ref
:常见于辅助索引的等值查找,或者多列主键、唯一索引中,使用第一个列之外的列作为等值查找会出现;返回数据不唯一的等值查找也会出现。range
:索引范围扫描,常见于使用<、>、is null、between、in、like等运算符的查询中。index
:索引全表扫描,把索引从头到尾扫一遍;常见于使用索引列就可以处理不需要读取数据文件的查询,可以使用索引排序或者分组的查询。all
:全表扫描数据文件,然后在server层进行过滤返回符合要求的记录。
4、ref
- 如果使用常数等值查询,这里显示const;
- 如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段;
5、Extra
using filesort
:排序时无法用到索引,常见于order by和group by语句中。using index
:查询时不需要回表查询,直接通过索引就可以获取查询的数据。