MySQL调优 - 索引原理及优化

Posted zero13_小葵司

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL调优 - 索引原理及优化相关的知识,希望对你有一定的参考价值。

我们来开启一个新的系列,mysql调优,这个系列我们写3个部分:

  1. mysql索引优化;
  2. mysql读写分离;
  3. mysql分表分库;
  4. mysql事务(该部分就不写了,一般不会去修改其读写类型,知道其默认的是可重复读级别);

这个系列的更新会比较快,结束之后我们就开启大数据的相关更新内容。

我们以索引展开MySQL的优化,因为这是MySQL读写高性能的基础,也是设计的关键与难点,当然并不是看完这三篇优化,数据库的东西就都搞定了,这和我们在具体业务开发中的场景依然密切相关,这篇优化可以说还只是入门,但不要看到这里说入门就觉得会简单,我可以负责任的说,有很多写了快10年代码,还不知道索引原理,甚至以写上百行的SQL引以为豪的资深研发人员。

我们依然不做过多展开,直接针对生产常用的InnoDB引擎来讲。

InnoDB简介

大家可能有印象,在创建数据库时会让我们选存储引擎,现在的类型更多了,这里分享的一些东西会是比较抽象的理论,能理解对后面的知识理解是有益的,实在觉得抽象,可以先大概记住,以后工作中慢慢体会。

存储引擎是针对表的,虽然我们在建库的时候就会选,但在建表时还能再指定,这个可以查看数据库的存储文件。

文件结构

InnoDB的表会有两种类型文件

frm文件:用于存储表结构及基本信息
ibd文件:用于存储索引及数据

InnoDB的数据库与索引是存在一起的,没有单独分文件,这样的设计与其索引的具体实现息息相关,这里我们只要先知道就好。

行与页

为了更好的检索性能,数据会以行与页的形式存储,行存储于页内,而页有页目录的存在,以帮助更好地检索到对应的页。

这里会涉及我们的第一个优化点,行数据尽量不要过大,我们记住下面几个点:

  1. 一行数据最大65535字节,如果是varchar去掉头尾还剩65533字节,当数据行过大时会行溢出;
  2. 行数据过大时会跨页,一页最大为16K,行数据跨页时会影响我们的查询性能;
  3. 大的数据字段使用blob格式,这样该数据会存储在别的地方;
  4. 字段长度尽量为2的次方,以便于尽量在多行时填满页,减少空隙提升空间利用与检索性能(页多了会影响检索性能);

锁与事务展开讲会很多,因为我们不打算专门讲,但还是提到一下,InnoDB支持行级锁以及事务,锁又分为读锁和写锁。

我们怎么防止脏读与幻读的呢?这与mysql的事务与锁机制都有关系。文中不做展开了,大概知道就好,一些知识我们会穿插在后面的讲解中出现。

索引

索引可以理解为书本的目录,那么是不是只要有目录就会很快呢?如果索引我们也要从头开始查找,有时也要找很久。那怎么办呢?我们再想想比如字典,还会把索引按一定的结构再组织,比如我们找H开头的,可以先找到H所在的位置,再在H内开始找。
数据库的索引也是如此,通过数据结构的组织,让我们的查询可以更快,即使是百万条数据,也不需要进行百万次检索,可以在3次便找到对应数据,那么这是什么索引呢?就是我们要讲到的innodb的索引B+树。

B+树

数据库的索引可以不止一种,比如可以采用hash的索引,这种索引以数组加链表的方式存储数据的地址值,通过值的hash命中对应的值,只要减少哈希碰撞,这个检索是非常快的,但是为什么我们不用呢?

hash是离散的,而我们的检索常常需要范围检索,对离散的数据我们如何来做范围检索呢?这个索引在这样的场景下就不适用了。

这里就到了B+树,那么既然是树,我们就会想到二叉树,balance tree等数据结构。

B+树也是一种数据结构,在具体实现时也是可以有差异的,比如InnoDB与MyISAM的B+树索引实现便是有差异的。前面我们提到,InnoDB的索引与数据是存储在一个文件内的,其表数据文件本身就是按B+树组织的一个索引结构文件。

在其内部会将建3层树结构,前两层为索引,最后一层叶子节点则包含了具体数据,数据以行与页的方式存储。而其索引节点则会记录该索引下对应的数据范围,那么我们就能快速定位到具体的数据了,而一共三层则让我们检索三次便能定位到数据所在位置。

数据库将定位的数据拿到内存中进行处理,这里不进行磁盘交互会快非常多,而新的MySQL数据库针对大内存,可以将索引放在内存中,也就是磁盘的IO交互可能只需要一次便好,这大大提升了查询的性能。

为什么要主键

说得直白点,我们不建主键数据库也会默默为我们建一个隐藏的主键来组织数据结构。

那么既然数据库自己会帮我们干这件事,为什么我们还要自己做呢?
如果我说,数据库都那么累了,这件小事我们自己干掉不好么?你们会信吗?

数据库发现你没有主键,然后自己去建,这也是额外的性能消耗,那么在建主键的时候,尽量使用自增,如果考虑到分布式、分库分表、数据迁移等不使用数据库自己的自增主键,也可以使用自己实现的自增主键,但是尽量使用顺序递增的,一来可以保证数据的连续性,二来利于数据库性能。

为什么连续的主键或索引有利于数据库性能呢?因为我们用的B+树啊,一个新数据进去后需要去根据其值做树的平衡,当一条新数据会插入原本的树节点时,必然引起树结构的变更,这样的性能消耗,必然比顺序往树后添加节点大很多,特别在数据量大了以后。

联合索引

上面我们讲到,MySQL的索引与数据文件是存在一起的,因此如何高效使用索引,也就成了我们重要的课题,那便是使用联合索引,根据业务的需要进行联合索引设计。

联合索引在设计时将最常用的查询字段排在越前面,因为联合索引在数据库的存储,会先根据排在前面的字段来建立树结构,因此这个字段既要有区隔性又尽量有连续性。

关于索引设计会有很多的知道文章,这里不做展开,但是从优化的角度我们尽量使用联合索引,而不是建很多的索引。

最左匹配

这一段内容与上一段内容密切相关,最左匹配便是依赖于联合索引。

这是什么意思呢?是说我们在查询时的where条件,会从最左边的查询条件开始看是否命中索引,如果第一个就无法命中,那么就会进行全表扫描。

这个如果理解了MySQL的B+树结构以及联合索引的存储方式,会很好理解。

下一个篇章我们分享:MySQL读写分离方案

以上是关于MySQL调优 - 索引原理及优化的主要内容,如果未能解决你的问题,请参考以下文章

MySQL调优 - 索引原理及优化

视频教程 | MySQL底层原理与性能调优

MySQL调优 - 读写分离

06: mysql索引查找原理及调优

MySQL调优 - 读写分离

MySQL调优 - 读写分离