前言
作者最近在学习数据库索引,故想通过写博客的方式记录学习情况,如有错误,敬请指出。
一、索引简介
1.1索引是什么
索引是一个单独的、存储在磁盘上的数据库结构,包含着对数据表里所有记录的引用指针。使用索引可以快速找出在某个或多个列中有一特定值的行,所有MySQL列类型都可以被索引,对相关列使用索引是提高查询操作速度的最佳途径。
1.2 索引的优劣势
优势:
- 可以提高数据检索的效率,降低数据库的IO成本
- 通过索引列对数据进行排序,降低了CPU的消耗
劣势:
- 占磁盘空间
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。
1.3 何时使用索引
- 当唯一性是某种数据本身的特征时,指定唯一索引。使用唯一索引需能确保定义的列的数据完整性,以提高查询速度。
- 在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引,如果待排序的列有多个,可以在这些列上建立组合索引。
二、索引的分类
2.1 单例索引
- 常规索引:常规索引是MySQL中的基本索引类型,允许在定义索引的列中插入重复值和空值
- 唯一索引要求索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一
- 主键索引是一种特殊的唯一索引,不允许有空值
2.2 组合索引
- 多个字段组合的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用。如果未使用中间的索引,后面的索引也会失效,使用组合索引时遵循最左前缀集合
聚集索引选取规则:
- 如果存在主键,主键索引就是聚集索引。
- 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
- 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索
引。
三、索引的使用
3.1 索引的基本命令
1.创建索引:
create index 索引名 on 表名(字段名(长度));
alter table 表名 add index 索引名(字段名(长度));
2.删除索引:
drop index 索引名 on 表名;
3.查看索引:
show index from 表名
3.2 判断索引是否生效
可以使用EXPLAIN语句查看索引是否正在使用。
explain select * from 表名 where 条件(条件需添加索引)
执行计划中各字段的含义:
3.3 避免索引失效
可以采用以下几种方式,来避免索引失效:
1.使用组合索引时,需要遵循“最左前缀”原则;
2.不在索引列上做任何操作,例如计算、函数、类型转换,会导致索引失效而转向全表扫描;
3.尽量使用覆盖索引(之访问索引列的查询),减少 select * 覆盖索引能减少回表次数;
4.MySQL在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描;
5.LIKE以通配符开头(%abc)MySQL索引会失效变成全表扫描的操作;
例如:
select * from company where companyName like ‘%江南皮革长’;
可以改为
select * from company where reverse(companyName) like reverse(‘%江南皮革长’);
6.字符串不加单引号会导致索引失效(可能发生了索引列的隐式转换);
7.当or连接的条件,左右两侧字段都有索引时,索引才会生效
四、索引实现原理(InnoDB)
在MySQL的索引结构中,选择的是B+Tree,那么什么是B+Tree呢?在说B+Tree前先介绍B-Tree
B-Tree(B树),B树是一种多叉路衡查找树,相对于二叉树,B树每个节点可以有多个分支,即多叉。
以一颗最大度数(max-degree)为5(5阶)的b-tree为例,那这个B树每个节点最多存储4个key,5
个指针:
特点:
- 5阶的B树,每一个节点最多存储4个key,对应5个指针。
- 一旦节点存储的key数量到达5,就会裂变,中间元素向上分裂。
- 在B树中,非叶子节点和叶子节点都会存放数据。
B+Tree是B-Tree的变种,我们以一颗最大度数(max-degree)为4(4阶)的b+tree为例,来看一
下其结构示意图:
最终我们看到,B+Tree 与 B-Tree相比,主要有以下三点区别:
- 所有的数据都会出现在叶子节点。
- 叶子节点形成一个单向链表。
- 非叶子节点仅仅起到索引数据作用,具体的数据都是在叶子节点存放的。
MySQL索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加一个指向相邻叶子节点
的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能,利于排序。
五、其他
5.1 回表查询
先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取数据的方式,就称之为回表查询。
当我们执行下图查询语句时,具体过程如下:
1.由于是根据name字段进行查询,所以先根据name='Arm’到name字段的二级索引中进行匹配查
找。但是在二级索引中只能查找到 Arm 对应的主键值 10。
2. 由于查询返回的数据是所有字段,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最终找到10对应的行row。
3. 最终拿到这一行的数据,直接返回即可。
5.2 覆盖索引
覆盖索引是指 查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到 。
5.3 前缀索引
当字段类型为字符串(varchar,text,longtext等)时,有时候需要索引很长的字符串,这会让
索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建
立索引,这样可以大大节约索引空间,从而提高索引效率。
create index idx_xxxx on table_name(column(n)) ;
总结
但愿吉祥