随记-数据库索引
目录
前言
在学习数据库三级的过程中,对索引的内容进行了简单的概括和介绍,从多方面进行解析。
一、索引概述
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构。这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
索引(数据结构):红黑树、二叉树、B-Tree、B+Tree
索引概述:
例如语句(select * from user where age = 45)
id | name | age |
1 | Zhangsan | 55 |
2 | lisi | 22 |
3 | wangwu | 11 |
4 | lierma | 42 |
5 | zhangfei | 56 |
6 | libai | 45 |
7 | huangzhong | 89 |
在无索引的条件下,会进行全表的扫描,数据会一行行的扫描性能低
id | name | age |
1 | Zhangsan | 36 |
2 | lisi | 22 |
3 | wangwu | 33 |
4 | lierma | 48 |
5 | zhangfei | 53 |
6 | libai | 29 |
7 | huangzhong | 45 |
8 | Machao | 17 |
9 | Anqila | 23 |
10 | wuzetian | 20 |
有索引:
如果像存在这样的二叉树,可以大大减少检索的效率
二、索引的优缺点:
优势 | 劣势 |
提高数据检索效率,降低数据库的IO成本 | 索引列需要占用空间 |
通过索引列对数据进行排列,降低数据排列成本,降低CPU的消耗 | 索引大大的提高了查询的效率,同时也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE时,效率降低 |
三、索引结构的实现
MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的结构
索引结构 | 描述 |
R+Tree索引 | 最常见的索引类型,大部分的引擎都支持B+树索引 |
Hash索引 | 底层数据结构是使用哈希表实现的,只有精确匹配索引列的查询才有效,不支持范围查询 |
R-tree(空间索引) | 空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少 |
Full-text(全文索引) | 通过建立倒排索引(了解过es的都知道),快速匹配文档的方式,类似于Lucene,Solr,ES |
索引结构:
索引 | InnoDB | MyISAM | Memory |
B+tree索引 | 支持 | 支持 | 支持 |
Hash索引 | 不支持 | 不支持 | 支持 |
R-tree索引 | 不支持 | 支持 | 不支持 |
Full-text索引 | 5.6版本后支持 | 支持 | 不支持 |
平常我们说的索引,没有特别的指明,都是指B+树组织结构的索引
四、索引结构——二叉树
- 二叉树索引相对于无索引的全表扫描显然能够大大提高查询的效率,但是也存在缺点:顺序插入时,会形成一个链表,查询性能大大降低。大数据量情况下,层级较深检索速度慢。
- 为了解决二叉树的顺序加入问题产生了红黑二叉树,虽说解决了顺序插入形成链表的问题,但是还是存在:大数据量的情况下,层级较深,检索速度慢。
- B-Tree(多路平衡查找树)的出现解决了二叉树的顺序平衡问题,一颗最大度数(max-degree)为5(5阶)的b-tree为例(每个节点最多存储4个key,5个指针)
如图:20,30,62,89为key,存在五个指针指向第二层的五个节点
注意:树的度数是指一个节点子节点的个数
五、索引结构——B+Tree
在B树之后人们不断的完善索引结构,产生了B+Tree
最大度数(max-degree)为4(4阶)的B+tree
MySQL索引数据结构对经典的B+Tree进行了优化,增加了一个指针指向相邻叶子节点的链表指针,形成了带有顺序指针的B+Tree,提高区间访问的能力
经典
MySQL优化
注意:B+Tree与B-Tree的区别
- B+Tree所有数据都只会出现在叶子节点
- 叶子节点形成一个单项的列表
六、索引结构——Hash索引
Hash索引采用一定的hash算法,将键值换算成新的hash值映射到对应的槽位上 ,然后存储在hash表中,如果两个(或者多个)键值,映射到一个相同的槽位上,就会产生hash冲突(也叫hash碰撞),可以通过链表来解决
特点:
- Hash索引只能用于对等比较(=,in),不支持范围查询(between,>,<....)
- 无法利用索引完成排序操作
- 查询效率高,通常只需要一次检索即可,效率通常高于B+Tree
存储索引支持
在MySQL中,支持hash索引的是Memory引擎,而InnoDB具有自适应的hash功能,hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的。
为什么InooDB存储引擎选择使用B+tree索引结构?
- 相对于二叉树,层级更少,搜索效率更高
- B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;
- 与Hash索引相比,B+Tree支持范围匹配及排序操作
七、索引的分类
分类 | 含义 | 特点 | 关键字 |
主键索引 | 针对于表中主键创建的索引 | 默认自动创建,只有一个 | PRIMARY |
唯一索引 | 避免同一个表中某数据列中的值重复 | 可以有多个 | UNIQUE |
常规索引 | 快速定位特定数据 | 可以有多个 | |
全文索引 | 全文索引查找的是文本中的关键词,而不是比较索引中的值 | 可以有多个 | FULLTEXT |
在InooDB存储引擎中,根据索引的存储形式,可以分为
分类 | 含义 | 特点 |
聚集引擎(Clustered Index) | 将数据存储与索引放到一块,索引结构的叶子节点保存了行数据 | 必需有,且只有一个 |
二级索引(Secondary Index) | 将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键 | 可以存在多个 |
八、聚集索引的选取规则:
- 如果存在主键,主键索引就是聚集索引
- 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引
- 如果没有主键,或者没有合适的唯一索引,则InooDB会自动生成一个rowid作为隐藏的聚集索引。
索引语法
创建索引:CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name (index_col_name....)
查看索引:SHOW INDEX FROM table_name
删除索引: DROP INDEX index_name ON table_name
- create index index_name on tb_user(name);
- Create unique index index_phone on tb_user(phone);
- Create index index_pas on tb_user(profession,age,status);
- Create index index_email on tb_user(email);
九、索引的使用:
1.盖索引覆
尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中全部能够找到),减少select *的使用
在查看索引中(using index condition是查找使用到了索引,但是需要回表查询数据,using where;using index 查找使用了索引,但是需要的数据在索引列中都能够找到,所以不需要回表查询数据)
例如存在如下表:
表中会存在聚集索引,我们再根据表中的name建立一个辅助索引(二级索引)
当我们执行语句:select id,name from tb_user where name = ‘Am’;
可以发现他会访问辅助索引,在辅助索引中他可以找到他想要的id,name不需要进行回表查询,这个被叫做覆盖索引,就是在辅助索引(二级索引)中找到自己想要的所有数据这个就叫做覆盖索引。
一张表,四个字段id,username,password,status数据量大,需要对SQL进行优化,下列语句如何优化
Select id,username.password from tb_user where username = ‘itcast’;
应该是可以考虑建立一个联合索引,这要查找的速率应该是有所提高
Create index index_i_u_p on tb_user(username,password);
2.前缀索引
当字段类型为字符串(varchar,text),需要索引很长的字符串,索引会变得很大,查询时浪费大量的磁盘IO,影响查询效率,此时可以只将字符串中的一部分前缀,建立索引,这样可以大大节省索引空间,从而提高索引效率
语法:
Create index idx_xxx on table_name(column(n));
前缀长度:
可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的
Select count(distinct email)/count(*) from tb_user;
Select count(distinct substring(email,1,5))/count(*) from tb_user;
从上图需要注意的是:当我们创建了前缀索引的时候,他会创建如上的索引结构,我们进行如下的SQL语句 : select * from tb_user where email = ‘lvbu666@163.com’,他会查找如上图的辅助索引然后进行回表查询
3.单列索引与联合索引
单列索引:即一个索引值包含单个列
联合索引:即一个索引包含了多个列
在开发中如果存在多个查询条件,考虑针对查询字段建立索引的时候,建议建立联合索引,而非单列索引
注意:多条件联合查询的时候MySQL优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询
十、索引设计原则:
- 针对数据量较大,查询比较频繁的表建立索引
- 针对常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引
- 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高
- 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引
- 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率
- 要控制索引的数量,索引并不是多多益善,索引越多,维护索引的代价越大,会影响增删改的效率
- 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束,当优化器知道每列是否包含NULL值时,他可以更好地确定哪个索引最有效的用于查询