索引
聚集索引和普通索引
MySQL数据库的B+tree索引可以分为两大类,一类叫聚集索引,一类叫非聚集索引(普通索引)。
InnoDB存储引擎表是索引组织表,聚集索引其实就是一种索引组织形式,索引键值的逻辑顺序决定了表数据行的物理存储顺序。聚集索引叶子节点存放表中所有行数据记录的信息,所以经常会说数据即索引,索引即数据,这是针对聚集索引来说的。在创建一张表时,要显示地为表创建一个主键(聚集索引),如果不主动创建主键,那么InnoDB会选择第一个不包含有null值地唯一索引作为主键。如果连唯一索引都没有,InnoDB就会为该表默认生成一个6字节的rowid作为主键。
普通索引在叶子节点并不包含所有行的数据记录,只是会在叶子节点存有自己本身的键值和主键的值。在检索数据时,通过普通索引叶子结点上的主键来获取想要查找的行数据记录。
主键索引和唯一索引
主键索引就是聚集索引,每张表中有且仅有一个主键,可以由表中一个或者多个字段组成。主键索引必须满足三个条件,主键值必须唯一;不能包含null值,一定要保证该值是自增属性。使用自增列作为主键,可以保证写入的数据顺序也是自增的,这就在很大程度上提高了存取效率。
创建主键的语法:
alter table table_name add primary key(column);
唯一索引是约束条件的一种,其实就是不允许有重复的值,但是可以允许有null值。上面说过表中只能有一个主键,但是唯一索引可以有多个。
创建唯一索引的语法:
alter table table_name add unique (column);
覆盖索引
MySQL只需要通过索引就可以返回查询所需要的数据,而不必在查询到索引之后再去回表查询数据了,这样就减少了大量的I/O操作,查询速度也是相当快。在执行计划的extra列中会出现Using index的关键字。比如查询语句select id from t where name='name11'G;,在这条查询语句中,想要检索主键id字段,而且在查询条件中name字段是普通索引,之前讲过普通索引中包含主键的值,相当于(name, id)索引,那么这条语句就使用了覆盖索引,出现了Using index。
注意: 如果使用覆盖索引,一定要让select 列出所需要的列,坚决不可以直接写出select * 。
联合索引
联合索引又叫复合索引,是在表中两个或者两个以上的列上创建的索引。利用索引中的附加列,可以缩小检索的段池范围,更快的搜索到数据。创建语法和普通索引的创建一样。例如为表t的c1, c2字段创建一个联合索引语法:
create index idx_c1_c2 on t (c1, c2);
联合索引在使用的过程中,必须满足最左前缀原则。一般把选择性高的列放在前面。一条查询语句可以只使用索引中的一部分,但是必须是从最左侧开始。
可以用到c1索引和c1, c2索引。
以下查询可以使用到索引:
select * from t where c1=某值;
select * from t where c2=某值 and c1=某值;
select * from t where c1=某值 and c2 in (某值,某值);
select * from t order by c1, c2;
select * from t where c1=某值 order by c2;
反之,使用不到索引的情况:
select * from t where c2=某值;
select * from t where c2=某值 order by c1;
还有一种特殊的情况:
select * from t where c1=某值 or c2=某值;
虽然c1字段在前,但是这种情况是不能使用到索引的。这种情况可以在c1,c2字段上面建立两个单列索引。
哈希索引
哈希索引采用哈希算法,把键值换算成新的哈希值,这里需要注意哈希索引只能进行等值查询,不能进行排序,模糊查找,范围查询等。检索时不需要像B+tree那样从根节点到叶子节点逐级查找,只需要一次哈希算法即可立刻定位到相应的位置,查询速度非常快。例如,select * from zs where city_id=100 这样一条语句。哈希过程如下图:
索引的总结
索引的优点:
1) 提高数据检索的效率
2) 提高聚合函数的效率
3) 提高排序效率
4) 使用覆盖索引可以避免回表
索引创建的四个不要:
1) 选择性低的字段不要创建索引(例如, 性别sex, 状态status)
2) 很少查询的列不要创建索引(项目初期就要确定好)
3) 大数据类型字段不要创建索引
4) 尽量避免使用NULL,应该指定列为NOT NULL(在MySQL中,含有空值的列很难进行查询优化,它们会使得索引,索引的统计信息及比较运算更加复杂,可以使用空字符串代替空值)
使用不到索引的情况:
1)通过索引扫描的行记录超过全表的30%,优化器就不会走索引,而变成全表扫描,
2) 联合索引中,第一个查询条件不是最左索引列
3) 联合索引中,第一个索引列使用范围查询,只能使用到部分索引
4)联合索引中,第一个查询条件不是最左前缀列
5)模糊查询条件列最左以通配符%开始
6)两个单列索引,一个用于检索,一个用于排序。这种情况下只使用一个索引。因为查询语句最多只能使用一个索引,考虑建立联合索引。
7)查询字段上面有索引,但是使用了函数运算。