Mysql索引不会怎么办?6000字长文教会你

MySQL的索引入门真的很难吗

常常在开发中碰到同事说,数据查询好慢,第一个反应就是给表加个索引。从而引起想去探索下咱们常说的索引到底是什么?难道只须要加个索引就能解决数据库查询问题吗?mysql

带着这个问题咱们开始探究MySQL中的索引到底是什么,它能帮助咱们作些什么。sql

脑图

索引存在的意义

在现有程序业务中,数据库做为存储的重要一环,不可或缺,而对于数据库的操做无外乎是增删改查,但随着数据量的增长,数据库的性能就成为最重要的一环,数据查询不能慢,数据查询一慢,用户体验就会差。数据库

如何在保证数据存储中的增删改查效率呢?就成了一个必不可少的设计。编程

在Mysql这样的数据存储中老是少不了一个东西--->索引,索引就相似于咱们看书的目录,使用书籍的目录能够帮助快速的定位到知识点的页数,而索引也是一样的目的,快速检索到数据。数据结构

那就能够总结出索引的目的:提升数据的检索速度函数

索引的类型

既然索引有提升检索的速度,那就给数据库的查询操做都加上索引,让他们飞快的运行,这事还真不能急,为啥?数据库的索引种类有好多种,万一索引用的不对,引起的不是加快数据库的运行,而是众多的慢查询会将整个数据库拖垮。性能

用于提升读写效率的数据结构种类这么多,那咱们来了解下数据库中常见的索引类型都有哪些。优化

索引类型 哈希索引 二叉树 跳表 B+Tree

哈希索引

哈希索引简单来讲就是Key-Value模型,咱们只要经过给定的Key就能够查找到对应的Value,十分快速方便。spa

不过你要明白哈希索引是经过哈希函数对Key进行计算,换算成数据存储位置,随着数据量的增长,不可避免会出现不一样的Key通过哈希函数计算后出现相同的数据存储位置。设计

这种状况怎么解决呢?业界通用的方式是当出现位置同样的数据结果,会在该结果后面连接一个链表,将相同的数据放入到链表中。

更进一步当相同位置中的数据愈来愈多,查询数据时会将链表中的数据遍历,速度也是慢,这时候能够采用将链表进行树化,二叉树的查找速度仍是很快的。

⬇️图是数据举例说明:

哈希索引

哈希索引只适合用来查找等值的数据,而不是适合范围索引,排序等操做。常见的哈希索引是在Redis中。

二叉树

数据结构中存在数据结构,虽然树的结构多种多样,可是经常使用的数据结构是二叉树,二叉树是拥有两个分叉的树,分别为左子节点与右子节点。以此类推,动物中有八爪鱼,一样的也存在八叉树,你能够想象八叉树是什么样子。

二叉树的特色是,左节点的值<父节点<右节点。若是要查找到一个值就能够按照子节点的顺序进行查找.

随着数据量的增大,二叉树的高度也会主键递增,数据库存储的数据并非都放到内存中,而是要放到磁盘上,磁盘的访问速度是比内存慢几十倍。

如今假如一个树高30,每次搜索树一次就须要访问一次硬盘,一次访问磁盘速度假设是10ms,树高30至少须要访问磁盘30次才能获取到数据,30*10=300ms。

若是数据更多,树高到100,获取一次数据成本就很高了。

为了解决这个问题,可使用N叉树的方式来下降树的高度,减小访问磁盘的次数,这样就能提升效率。

二叉树

跳表

跳表是创建在多层级链表上的数据结构,经过一层层的链表查询就提升了检索数据的效率。

B+Tree

Mysql中索引的实现是创建在数据库引擎上的,而在Mysql中有多个数据库引擎,经常使用的数据库引擎是InnoDB.

InnoDB引擎索引实现是使用B+Tree索引模型,其实还有一种BTree模型,B+Tree是创建在BTree基础上发展的。

B+Tree能够认为是BTree的改进版本:

注意子节点与叶子节点是不一样的概念。把没有子节点的节点叫作叶子节点

  • 在B+Tree中子节点只存储索引,而在B树中是存储数据的。
  • B树中的叶子节点并不须要使用链表连串联,而B+树中是用链表链接起来的。
  • B+树中的叶子节点存储数据.

数据库中每个索引都能对应到一颗B+树,一个表是能够存在多个B+树。

不论是B+Tree仍是BTree都是利用多叉树(该树有多少叉是根据页的大小进行计算好的,索引会涉及到新增删除,一样的就会涉及到页的分裂与合并),保证不把全部的索引数据放入到内存上,下降磁盘的访问次数加快数据访问。

索引的分类

Mysql中经常使用Innodb引擎,组织数据库索引的方式就是B+Tree。

B+Tree是索引组织表,那在B+Tree有多少种索引的类型呢?

从不一样的方向划分能够划分为不一样的类型。

功能上区分

主要为普通索引,主键索引,惟一索引,前缀索引,全文索引,哈希索引。

普通索引

普通索引就是咱们经常使用的索引建立-> 建立单个索引,相关语句以下

alter table table_name add index index_name(column);
drop index index_name on table_name;
ALTER TABLE table_name DROP INDEX index_name
复制代码

主键索引

主键索引是在普通索引的基础上增长两种约束条件分别为惟一和不能为空。主键索引在Innodb中用来维护索引组织的性质,因此,在使用Innodb引擎时,建议你的表都设置主键。

建立主键能够在建立的表的时候指定 primary key('id'),也能够建立联合主键primary key ('id','name').

建立主键的相关SQL

# 当表里面没有主键索引时,增长主键索引
ALTER TABLE table_name ADD PRIMARY KEY ( `id` )
# 删除主键索引
ALTER TABLE table_name DROP INDEX name_index
复制代码

惟一索引

惟一索引时在普通索引的基础上增长惟一的约束,在插入相关数据时,会检查该索引数据是否已经存在数据库中。

使用下面的建立语句建立:

# 建立惟一索引
ALTER TABLE table_name ADD UNIQUE (`column`)
# 删除索引
drop index index_name on table_name;
复制代码

前缀索引

字符串在编程中常常遇到的,好比经常使用的邮箱,一些业务场景中须要对某些字符串的前缀进行匹配。

这就涉及到一个问题,不能使用索引的话,就只能进行全表扫描。数据量一大,该方式就会成为性能的瓶颈。

数据库中的前缀索引就是解决字符串前缀匹配的问题。

# 建立前缀索引
alter table table_name  add index index_name(columns(6));
# 删除索引
drop index index_name on table_name;
# 怎么计算前缀索引设计几个字符 使用下列语句进行估算
select count(distinct 列名)/count(*)as a,COUNT(DISTINCT left(列名,100)) as b, COUNT(DISTINCT left(列名,110)) as c from 表名
复制代码

前缀索引有一个缺点就是没法使用覆盖索引的优化,必须回表查询。

全文索引

全文索引是用来解决Mysql中文本匹配慢的问题,常使用like模糊搜索%内容%,无法用到前面列举的索引,这时候就能够尝试使用全文索引来解决该问题。

相关SQL文件看下👇

create fulltext index table_name
    on index_name(column,column);
alter table table_name
    add fulltext index index_name(column,column);
复制代码

注意一点的是全文索引是有本身的匹配语法,使用match和against关键字来进行匹配👇。

select * from table_name where match(column,column) against('xxx xxx');
复制代码

从索引个数上区分

从个数区分就是该索引邮几个列组成。当有多个列构成就是联合索引

  • 单个索引:只有一列建立的索引
  • 联合索引:多列联合组成的索引。

单个索引的介绍不用多说,这里主要说下联合索引。

联合索引

咱们知道B+Tree树这种形式的索引结构是可使用最左前缀,来定位记录。十分恰当的联合索引就须要使该规则才能发挥出强大的做用。

最左前缀

顺便引出的问题就是咱们在建立联合索引的时候应该怎么安排索引内的字段顺序?

当当前表是新创建的,尚未其余索引能够根据业务需求进行直接建立;若是表中已经存在其余索引,那能够经过调整顺序帮助减小索引的建立。

每次建立一个新的索引,就会增长一部分的索引存储空间,随着数据量的增长,索引的存储也会暴涨,因此在建立索引时,都须要考一个空间占用的原则。

当有一个大字段和小字段组合成联合索引时,大字段索引放在联合索引的前面

好比如今须要根据邮件和年龄查询数据,但还有根据age以及email单独查询的需求。

通常第一个反应就是建立三个索引,age,name,(name,age)/(age,name)。

而通常email的长度是大于age的,在有最左前缀的原则下,联合索引第一个字段单独查询是可使用索引。则这里选择建立的索引就是age,name,(name,age)。

从磁盘角度区分

看一些数据库资料老是聚簇索引,非聚簇索引,这两种方式跟主键索引,普通索引又有什么区别?

聚簇索引,非聚簇索引

其实就是一类内容,只是根据分类的方式不一样,叫的名字不一样而已。聚簇索引与非聚簇索引是指在磁盘上对数据的组织结构不一样。

聚簇索引可认为是磁盘将实际数据按照定物理地址进行顺序存放,而且与索引的顺序是一致的。那么当索引是相邻的,对应的数据必定也是按照相邻的顺序存放。

磁盘对于顺序读取速度比磁盘随机读取的速度要快不少;正由于聚簇索引是按照物理顺序进行存储,那一个表只能有一个聚簇索引,该索引在Mysql中是主键索引,固然主键索引也是能够包含多个列的。

其余类型的索引都是被称为非聚簇索引。

非聚簇索引
)

使用非聚簇索引查询数据,目的是先查到对应的聚簇索引也就是主键索引。经过主键索引从而查询到对应的数据。在这个过程当中还涉及到两个技术,分别为回表以及索引下推。

回表

回表很见到就是经过其余索引查到对应的主键值,再使用主键值去表里面再检索一遍数据。

那有没有不用回表?有的,在查询的数据的时候,查询的索引中已经包含要的字段,就不须要再使回表使用主键查询数据,这句话可能有点蒙,看下SQL你就明白了。

# 设置userid为普通索引
# 不使用覆盖索引,须要回表查询
select * from user where userid=1
# 使用了覆盖索引,这是由于userid的索引列上叶子节点就是存储的主键id,不须要再回表
select ID from user where userid=1;

# 使用联合索引也是能够作到的(userid,name)作一个联合索引,索引列上有对应的值,则不须要再回表查询
select name from user where userid =1
复制代码
索引下推

在Mysql5.6版本之前,查询到的数据每条都须要从新回表查询一次,而在5.6版本增长索引下推技术后,能够直接在索引列中过滤掉不须要数据,减小回表的次数。

注意该技术须要使用范围是联合索引(age,sex)

select * from user where  10<age and age>20 and sex=1;
复制代码

首先使用索引查询到年龄知足第一条大于10小于20的人,同时索引列能够直接进行判断该用户性别是否是知足1(男性),是就继续,不是该条记录过滤掉。

而在5.6之前知足大于10小于20后,根据读取到主键数据再进行对比。回表的次数天然比使用索引下推技术版本多。

总结

本章从一个小问题引起了对索引的探索,包含对现有的数据库中经常使用的几个索引技术进行介绍,明白为何Mysql会选择B+Tree做为索引的检索方式,并经过此方式梳理了Mysql中现有的索引技术。

但愿这边索引文章能帮助到你对索引的理解。

相关文章
相关标签/搜索