MySQL(六)------索引结构的理解

一、mysql索引从数据结构角度

1、B+树索引

O(log(n))

B+树是从平衡二叉树演化来的,但是并不代表B+树就是一个二叉树。

BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型。

为什么采用平衡查找树

B+树是一种平衡查找树,为什么不直接使用二叉树,很好理解,提高查找效率,防止二叉树因数据的插入导致节点层级过高。参考jdk8中对HashMap底层数据结构的改进,当链表上个数超过8的时候,转换为红黑树(平衡查找树)。

在这里插入图片描述
(效率较低的二叉查找树)

既然二叉查找树效率过低,那么为什么不采用平衡二叉树呢?

平衡二叉树,任何节点间子树的高度差不超过1,查找性能比较高。但是维护一棵平衡二叉树的代价非常大。

在这里插入图片描述
(平衡二叉树)

当插入新的键值(9),需要做如下变动

在这里插入图片描述
PS:引入网上图片

维持一棵平衡二叉树的开销相对比较大的

B+树特征

在这里插入图片描述

  • B+树的磁盘读取代价低:分支节点没有存储数据,磁盘读取,可以容纳更多的内部节点;
  • B+树的查询效率更加稳定:分支节点都是叶子节点的索引,任意关键字的查找都必须从根节点走到分支节点,所有关键字查询路径长度相同,每个数据查询效率相当;
  • B+树便于执行扫库操作:B+树的数据都存储在叶子节点上,分支节点均为索引,只需扫一遍叶子即可;
  • 方便范围查询:所有叶子节点形成有序链表,方便范围查询。

2、hash索引

innodb本身的索引结构是B+tree索引,innodb会自动监控索引表,对应频繁访问的索引(热点数据),在B+树索引基础上建立hash索引,来提高查找效率,但是对于客户端是不可控的,隐式的。

hash索引特点

不支持范围查询:只支持包括 “=” "in "在内的等值查询,不支持范围;

不支持前缀匹配查询:对于%的模糊查询,hash索引不支持前缀匹配查询

不能避免读取行:哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能的影响并不明显。

无法用于排序:Hash索引是通过hash函数将,键值直接映射为物理存储地址,使时间复杂度降低到O(1).本身存储是无序的,所以不能通过hash索引避免排序

无法使用部分索引列匹配查找:对于联合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。

存在Hash冲突:hash索引本质采用hash表实现,当存在大量hash冲突,会采用链表结构。比如对性别、学历等进行索引,因字段值重复性高,hash索引定位时,会造成命中查询效率低下。

3、FULLTEXT索引

full-text主要是用来代替like "%***%"效率低下的问题

全文索引使用条件

表的存储引擎是MyISAM,默认存储引擎InnoDB不支持全文索引(新版本MYSQL5.6的InnoDB支持全文索引)

字段类型:只有字段类型为char、varchar和text的字段才能设置全文索引。

MySQL自带的全文索引只能对英文进行全文检索,目前无法对中文进行全文检索。

如果需要对包含中文在内的文本数据进行全文检索,我们需要采用Sphinx(斯芬克斯)/Coreseek技术来处理中文

MySQL全文索引所能找到的词的默认最小长度为4个字符,使用MySQL自带的全文索引时,如果查询字符串的长度过短将无法得到期望的搜索结果

如何使用全文索引

alter table table_name add fulltext index(filed_1,filed_2);

SELECT * FROM table_name WHERE MATCH (filed_1,filed_2) AGAINST ('keyword');

4、R-Tree索引

r-tree在mysql很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有myisam、bdb、innodb、ndb、archive几种。

二、按照索引种类来分

1、主键索引

设定为主键后数据库会自动建立索引

2、唯一索引

索引列的值必须唯一,但允许有空值

3、单列索引

即一个索引只包含单个列,一个表可以有多个单列索引

4、多列索引(复合索引)

即一个索引包含多个列

5、全文索引

对文本的内容进行分词,进行搜索

三、创建索引的原则

1、更新频繁的列不应设置索引

2、数据量小的表不要使用索引

3、区分度不大,重复数据多的字段不应设为索引(如性别)

4、where 和 order by 涉及的列应考虑建立索引

5、业务上具有唯一特性的字段,即使是多个字段的组合,也建议建成唯一索引

四、mysql使用索引注意事项

1、使用!=以及<>不等于的时候,mysql不使用索引

2、当在字段时候函数的时候,mysql无法使用索引

3、在组合索引里使用非第一个索引时也不使用索引

4、在使用like的时候,以%开头,即"%***"的时候无法使用索引;在使用or的时候,要求or前后字段都有索引

5、避免对字段进行null的判断,因为索引不会生效(默认设置空字符串)

6、使用exist代替in(表中数据越多,exist的效率就比in要越大)

7、数据类型隐形转换,索引不会生效,如select * from user where age='20',age表字段类型为int,正确select * from user where age=20;

8、联合索引必须要按照顺序才会生效。如联合索引index(name,age),

9、不要使用 select *

10、多表关联,关联字段一定要有索引

11、执行计算不会命中索引,如:select * from test where a + 1 < 5

12、联合索引如果查询条件不包括索引最左边的字段,不能命中索引。如index(a,b) ; select * from user where b = 'xxxx' 不生效

13、范围条件查询可以命中索引,但是查询条件中用到两个范围列,则只有第一个会用到索引。select * from test where a > 5 and b < 10

14、范围查询和等值查询同时存在,优先匹配等值查询的索引select * from test where a = 1 and b < 10

五、如何创建索引

1、创建索引

#-创建普通索引
CREATE INDEX index_name ON table_name(col_name)
#创建唯一索引
CREATE UNIQUE INDEX index_name ON table_name(col_name)
#创建普通组合索引
CREATE INDEX index_name ON table_name(col_name_1,col_name_2);
#创建唯一组合索引
CREATE UNIQUE INDEX index_name ON table_name(col_name_1,col_name_2);

2、通过修改表结构创建索引

ALTER TABLE table_name ADD INDEX index_name(col_name);

3、创建表时直接指定索引

CREATE TABLE table_name (
    ID INT NOT NULL,col_name VARCHAR (16) NOT NULL,INDEX index_name (col_name)
);

4、删除索引

#直接删除索引
DROP INDEX index_name ON table_name;

#修改表结构删除索引
ALTER TABLE table_name DROP INDEX index_name;

如果你觉得本篇文章对你有所帮助的话,麻烦请点击头像右边的关注按钮,谢谢!

技术在交流中进步,知识在分享中传播

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章