一:索引优势劣势
优势
1) 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。
2) 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
劣势
1) 实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的。
2) 虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
二: 索引分类
1) 单值索引 :即一个索引只包含单个列,一个表可以有多个单列索引
2) 唯一索引 :索引列的值必须唯一,但允许有空值
3) 复合索引 :即一个索引包含多个列
三:索引语法
1)创建普通索引
-- 语法
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[USING index_type]
ON tbl_name(index_col_name,...)
index_col_name : column_name[(length)][ASC | DESC]
-- 语法说明
-- [UNIQUE|FULLTEXT|SPATIAL]索引类型,可选
-- index_name :索引名称
-- [USING index_type]:指定索引类型,如果不指定默认的是BTree ,可选
-- tbl_name:表名
-- index_col_name:字段名
-- 举例(对city表的city_name字段创建名为idx_city_name 的索引)
create index idx_city_name on city(city_name)
2)查看索引
-- 语法
SHOW INDEX FROM table_name;
-- 语法说明
-- table_name:表名
3)删除索引
-- 语法
DROP INDEX index_name ON tbl_name;
-- 语法说明
-- index_name:索引名称
-- tbl_name:表名
4) ALTER命令
-- 1). 添加一个主键索引,这意味着索引值必须是唯一的,且不能为NULL
alter table tb_name add primary key(column_list);
-- 2). 添加唯一索引(除了NULL外,NULL可能会出现多次)
alter table tb_name add unique index_name(column_list);
-- 3). 添加普通索引, 索引值可以出现多次。
alter table tb_name add index index_name(column_list);
-- 4). 该语句指定了索引为FULLTEXT, 用于全文索引
alter table tb_name add fulltext index_name(column_list);
-- 语法说明
-- tb_name:表名
-- index_name:索引名
-- column_list:一个或者多个字段
四: 索引设计原则
- 对查询频次较高,且数据量比较大的表建立索引。
- 索引字段的选择,最佳候选列应当从where子句的查询条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。
- 使用唯一索引,区分度越高,使用索引的效率越高。
- 索引可以有效的提升查询数据的效率,但索引数量不是多多益善,索引越多,维护索引的代价自然也就水涨船高。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护代价,降低DML操作的效率,增加相应操作的时间消耗。另外索引过多的话,MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价。
- 使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率。
- 利用最左前缀,N个列组合而成的组合索引,那么相当于是创建了N个索引,如果查询时where子句中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率。
1)创建复合索引
-- 最左索引举例(对tb_seller表的NAME,email,STATUS的这些字段,创建复合索引,索引名idx_name_email_status )
create index idx_name_email_status on tb_seller(NAME,email,`STATUS`);
--就相当于
-- 对name 创建索引 ;
-- 对name , email 创建了索引 ;
-- 对name , email, status 创建了索引 ;
五:避免索引失效
1). 全值匹配 ,对索引中所有列都指定具体值。
-- 对name、status 、address 创建联合索引。全都使用了,索引生效
explain select * from tb_seller where name='小米科技' and status = '1' and address = '西安市'
2). 最左前缀法则(复合索引中应该遵循的,必须包含联合索引的最左列),也就是使用了左面的索引,下一个索引才能生效。
-- 对name、status 、address 创建联合索引
-- 索引中不能跳过中间索引
explain select * from tb_seller where name='小米科技' -- 索引生效
explain select * from tb_seller where name='小米科技' and status = '1' -- 索引生效
-- 索引生效,和where后使用的顺序无关
explain select * from tb_seller where status = '1' and address = '西安市' and name='小米科技'
-- 部分索引失效,只有name索引生效,因为跨越了status,所以address索引失效
explain select * from tb_seller where name='小米科技' and address = '西安市'
-- 索引失效,因为没有从最左面的列开始
explain select * from tb_seller where status = '1' and address = '西安市'
3). 范围查询右边的列,不能使用索引 。
-- 对name、status 、address 创建联合索引
-- 部分索引失效,只有name,和status索引生效,因为使用了大于(>),所以address索引失效
explain select * from tb_seller where name='小米科技' and status > '1' and address = '西安市'
4). 不要在索引列上进行运算操作, 索引将失效。
-- 对name、status 、address 创建联合索引
-- 索引失效
explain select * from tb_seller where substring(name,3,2) = '科技'
5). 字符串不加单引号,造成索引失效(针对数字字符串的)。
-- 对name、status 、address 创建联合索引
-- 部分索引失效,name索引失效,但是status索引不生效
explain select * from tb_seller where name='小米科技' and status = 1
6). 尽量使用覆盖索引,避免select *。覆盖索引(只访问索引的查询(索引列完全包含查询列))
-- 对name、status 、address 创建联合索引
-- 虽然where中的索引生效了,但是查询列如果使用的是非索引中的字段,会回调查询
explain select name from tb_seller where name='小米科技'
7). 用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
-- 对name、status 、address 创建联合索引
-- 索引失效,虽然name有索引,但是or后面的字段没有索引,导致所有的索引失效
explain select * from tb_seller where name='小米科技' or nickname = '小米官方旗舰店'
8). 以%开头的Like模糊查询,索引失效。
-- 对name、status 、address 创建联合索引
-- 索引生效
explain select * from tb_seller where name like '科技%'
-- 索引失效(可以通过覆盖索引解决,也就是查询列是索引字段)
explain select * from tb_seller where name like '%科技'
9). 如果MySQL评估使用索引比全表更慢,则不使用索引。(9和10道理相同)
出现情况:数据量大,并且where条件的字段重复的多,可以索引失效,不走索引。
10). is NULL , is NOT NULL 不一定索引失效。(9和10道理相同)
索引字段的值 少量是null的时候,就走索引,is not null 同理
11). in 走索引, not in 索引失效。
六: 单列索引和复合索引。
尽量使用复合索引,而少使用单列索引 。如果对name、status 、address 创建联合索引,和分别对它们创建单独索引,数据库在查询多个字段的时候,单独索引只能生效一个。