Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySql索引原理和SQL优化

MySql索引原理和SQL优化方式

作者:小辛学西嘎嘎

索引是提升数据库查询效率的有序存储结构,包括主键索引、唯一索引、普通索引等,约束则用于数据完整性,包含主键、唯一、外键等约束,B+树是常用的索引结构,减少磁盘IO次数,索引应用场景包括where、groupby、orderby

一、索引与约束

1、索引是什么

索引是一种有序的存储结构,它按照单个或者多个列的值进行排序。

并且它分为:主键索引、唯一索引、普通索引、组合索引、以及全文索引。

我们使用索引的目的就是为了提升搜索的效率。

2、索引的分类

列的属性-索引约束

-- 主键索引
PRIMARY KEY(key1, key2)

--唯一索引
UNIQUE(key)

--普通索引
INDEX(key)
-- OR
KEY(key[,...])

--组合索引
INDEX idx(key1,key2[,...]);
UNIQUE(key1,key2[,...]);
PRIMARY KEY(key1,key2[,...]);

约束:为了实现数据的完整性,对于 innodb,提供了以下几种约束,primary key,unique key,foreign key,default,not null;

其中外键约束:用来关联两个表,来保证参照完整性;MyISAM 存储引擎本身并不支持外键,只起到注释作 用;而 innodb 完整支持外键,并具备事务性;

创建主键索引或者唯一索引的时候同时创建了相应的约束;但是约束时逻辑上的概念;索引是一个数据结构既包含逻辑的概念也包含物理的存储方式;

数据结构

索引包括多种数据结构,其中最常用的就是B+数索引,hash索引,全文索引。我们本文主要讨论的是在InnoDB引擎中所使用的B+数索引。那么为什么我们不使用红黑树呢?

首先B+树全称:多路平衡搜索树。对于瘦高的红黑树来说B+树是胖矮的。我们把所有的数据存放在叶子节点中,而且叶子节点还串联在一起,一个页中可以存放几个叶子节点,而非叶子节点存放索引内容,并且也放在页中,我们可以看下图。

当我们查找一个数据的时候,可以使用更少的磁盘IO就可以获得想要的数据。比如我们想要查找25这个节点的数据,先查找第一个页,找到25的位置,在看第二个页,,在找到第一个叶子节点,然后平移过去找到25这个节点,一共有4次磁盘IO(每次查找页就是一次IO)。

但是使用的是红黑树的话,那么就不止4次的磁盘IO了。当然除了更少的磁盘IO后,也是为了方便范围查找。对于B+树来说,他的叶子节点都串联在一起,当找到第一个节点之后,就可以相继找出其他节点。但是红黑树来说的话,每次都要重新查找叶子节点。

总结:可以减少磁盘访问次数;用来组织磁盘数据,以页为单位,物理磁盘页一般为 4K,innodb 默认页大小为 16K;对页的访问是一次磁盘 IO,缓存中会缓存常访问的页; 平衡二叉树(红黑树、AVL 树) 特征:非叶子节点只存储索引信息,叶子节点存储具体数据信息;叶子节点之间互相连接,方便范围查询; 每个索引对应着一个 B+ 树;

索引实现-物理存储

innodb 由段、区、页组成;段分为数据段、索引段、回滚段等;区大小为 1 MB(一个区由 64 个 连续页构成);页的默认值为 16k;页为逻辑页,磁盘物理页大小一般为 4K 或者 8K;为了保证区中的页连续,存储引擎一般一次从磁盘中申请 4~5 个区;

3、使用索引的场景

我们每次搜索数据都是通过索引来实现的,其中在哪里可以使用到索引呢?是在where,group by,order by后面使用索引的。那么哪些场景不适合使用索引呢?首先就是没有where,group by,order by的地方,还有区分度不高的列,需要经常修改的列,表数据量少。

我们创建B+树类型的索引就是为了通过比较来找到我们所需要的数据,但是当区分度不高的时候,反而会降低速度,如果经常修改这个列,那么我们的B+的结构就要经常变化,更加影响速率,表的数据较少的时候,没有必要去创建索引,创建索引反而会浪费空间。

学习了上面所讲述的B+树和索引之后来想一下下面几个经典的面试题吧:

二、索引方式

1、聚集索引

按照主键构造的 B+ 树,叶子节点中存放数据页中,数据也是索引的一部分。

一般来说主键索引就可以作为聚集索引,当没有主键的时候,如果有唯一索引,那唯一索引也可以作为聚集索引。18

-- user表中 有id主键
select * from user where id >= 18 and id < 40;

我们通过上面的SQL语句,进行主键索引(聚集索引),从结构中查找18的位置,然后一层一层找,最后在叶子节点中找到,然后18到40的位置是连续的,我们节点的查找也是顺序的。并且这里的叶子节点,全部都是保存的数据。

2、辅助索引(二级索引)

叶子节点不包含行记录的全部数据,辅助索引的叶子节点中,除了用来排序的 key 还包含一个 bookmark ,该书签存储了聚集索引的 key;

-- user表 包含 id name lockyNum; id是主键,lockyNum 辅助索引;
select * from user where lockyNum = 33;

由于这里使用的是辅助索引,在辅助索引中,叶子节点中存储的并不是数据,而是主键的id,当我们通过辅助索引找到相应的位置之后,根据查找到的主键id,再进入聚集索引中,然后操作就是上面聚集索引的过程了。后面简称回表查询。

3、覆盖索引

从辅助索引中就能找到数据,而不需通过聚集索引查找;利用辅助索引树高度一般低于聚集索引 树;较少磁盘 IO;在实际中我们select后一定不要*,而是具体的写出想要查找什么字段。

4、最左匹配规则

对于组合索引,从左到右依次匹配,遇到 > < between like 就停止匹配;在下面的索引中,是组合索引,当我们使用id,name,age;id,name;id;这三种方式去索引的话,就可以走索引结构,但是一旦前面没有id之后,那么就不会走索引结构。也就是说,最左匹配规则,必须要按着从左往右的顺序来。

KEY(id,name,age)

5、索引下推

为了减少回表次数,提升查询效率;在 MySQL 5.6 的版本开始推出; MySQL 架构分为 server 层和存储引擎层; 没有索引下推机制之前,server 层向存储引擎层请求数据,在 server 层根据索引条件判断进行数据 过滤; 有索引下推机制之后,将部分索引条件判断下推到存储引擎中过滤数据;最终由存储引擎将数据汇 总返回给 server 层;

三、索引的失效和原则

1、索引失效

2、索引原则

四、怎么解决慢的问题

我们通过使用 EXPLAIN 来查看 SQL 语句的具体执行过程。 原理:模拟优化器执行 SQL 查询语句,从而知道 MySQL 是如何处理 SQL 语句的。

首先我们需要找到SQL这个语句在哪里,通过 show processlist 列出较慢的连接通道来 以及使用慢查询日志来找到具体的SQL语句。再分析SQL中我们要先查看在where、group by、order by中是否使用索引,如果没有使用,那么就可以考虑是否添加索引,然后继续优化SQL语句中in和not in 变成联合查询,并且减少整体的联合查询。以及一个隐形的问题:age问题,应该存储出生年月,让客户端进行计算年纪。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文