MySQL整体调优
那我从头开始讲吧,
首先MySQL的一个调优从初期从表的一个规划设计就得开始讲了,首先得说一下MySQL对于单行数据量的一个要求。MySQL它的底层的一个内存页的大小是16KB,那么 比如说我们设计一张表他的单行数据如果是16KB的话,那么我们一个MySQL的内存页就只能存放一条数据,这是非常恐怖的,那么如果我们一条数据是1KB的话,那么我们一个内存页就能存储16条数据。
为什么要提到这个内存页?因为MySQL的我们说到的这个内存页就是说几次IO,我们读一个内存页就要做一次IO,一次IO读取一个内存页的数据,所以,首先我们要保证MySQL单行数据量的值尽量要小,那如何做到单行数据量要尽量小呢?这就在设计初期需求分析的时候就要考虑到了,比如说我们要存放一个UUID,如果这个UUID是一个32位的UUID,那么我们就要将它定死为32位的,如果我们想要去容错,那么我们可以将它调整为33或34位。但是千万不要浪费MySQL的存储空间,因为存储空间一旦大了以后,就会影响我们B+树的一个高矮胖瘦吧,因为B+树它是一个高扇出性。
B+树的所有节点,每一个节点其实都是一个16KB的内存页,那么可以做一个简单的计算,对于一个3层高的B+树,如果它的根节点,它的根节点是一个16KB的内存页,只有一个,那么这16KB的内存也只用于存储指针,它这个指针会指向第二层,它的指针大小能存储1170个左右的向下指针,也就是说第二层能够有1170个16KB的内存页,那么第三层就有1170的平方个16KB的内存页,然后最终我们再乘以一个16,对于这些数据我们可以存放两千万条的数据的。但是对于16KB一条长度的数据,就是两千万除以16,也就是存不了多少条数据。这是从一开始就要保证的一个数据的大小。
包括像在这个做设计的时候,像一些Enum字段,当然我们MySQL是没有所谓的枚举的字段,但是比方说我们的“男”“女”,尽量地去使用tinyint,用0和1去表示,这样的话一个是除了检索快速以外,也就是没有汉语的这个成分,第二个就是可以控制我们数据量的大小,这样就是说能够增加我们同一高度下的B+树我们能够容纳数据的最高量。三层B+树的最高索引基本上是在三次IO索引,这是初期的一个设计。
到达第二步,我们的表设计完了,我们就要开始对表进行所谓的增删改查。
那么这个时候就要考虑到MySQL的这个索引,我们如何去设计这个索引。其实索引的这个设计,还是要根据需求而定的。
我们先来说MySQL的这个索引。有三种索引,聚簇索引,辅助索引还有覆盖索引。Emm聚簇索引每张表只有一个,也就是我们的PrimaryKey,主键ID;辅助索引是我们的一个自加的这些索引,每一个辅助索引都有一棵辅助索引的树;还有一个就是我们的覆盖索引,覆盖索引其实是没有树的,一会可以介绍一下。
嗯那么在我们进行程序设计的时候,这个sql设计的时候,首先要确保一点,不要使用select ,因为这个select 是没有办法避免去走这个覆盖索引或者是辅助索引的,因为select *
必须要走聚集索引,也就是说要走这个全表扫描,走聚集索引的话,因为它要拿到所有的数据,只有在聚集索引的B+树的一个叶子节点里边才有这些数据。当然如果一定要使用这个的话,那我就建议使用至少是MySQL5.6版本,因为MySQL5.6有一个离散读的优化,而且也有一个ICP的优化,对于select *
这样的话,对于查询的速度会比较快一些。
好继续来说索引。对于这个索引的设计我想着重说一下这个覆盖索引。
在对索引进行设计的时候,如果select N个字段,如果在这个前提下我们能够保证这N个字段都是可以作为这个索引的话,那么我们就这样去设计,因为这样的话我们就可以直接在辅助索引里边找到这些数据,因为辅助索引里边存储着主键索引,存储着索引的值。那么这样的话我们就可以避免这个回表的查询,这样的查询速度是非常快的。
这是对索引的这个介绍吧。
然后我们还要在书写sql的时候,额尽量地去使用我们的这个mysql的执行计划,去看我们的索引是否失效,因为在特定的场景和特定的函数下边,MySQL索引会失效的,这些都是比较细节的要注意的部分。
这是第二个阶段。
第三个阶段就是MySQL这个数据量的一个增长。就是mysql数据量增长以后,首先要考虑的就是,首先最简洁的就是一个数据的分区,partition分区,对于partition分区这一块的话,要根据业务需求去进行分区,比如说要用日期去分区,有的要用ID范围去分区,这都没有关系。但是它分区有一个极限性,也就是单台服务器上这个Mysql最多是支持1024个分区,那么一旦达到这个分区上限,像~bi~这些数据肯定是分区支持不了的,那么就要考虑下一部分调优。
下一部分调优就是,所有的MySQL表的这么一个垂直拆分和水平拆分。
先说一下垂直拆分吧,垂直拆分基本上是一个单表变多表。单表变多表有几个优点,第一个优点也就是起初所说的我们的一条数据,它存储的数据量越小,它的B+树,三层B+树所能容纳的数据量是越多的,那么这样的话他能够承载更多的数据,他一个分区能承载更多的数据,进而呢它多个分区就能承载更多的数据,这样呢它的一个查询就能越来越好,它的效果是累加的。但是呢它其实是有一定缺点的,因为我们在进行这个表的这个垂直划分的时候,还要考虑它的表的关联性,那么我们在使用这个MySQL的时候,进行这个数据查询的时候,一旦有这个表关联的话,它的这个性能上是要多加考量的,就是说要做一定的测试。最好的一种场景就是,这两个表的数据拆分开来之后,每一张表它还能够去支持特定的业务线,这个时候基本上就是肯定要看相对的业务的选取,不同的业务可能有不同的设计方式。
再说一下这个水平拆分。水平拆分应该是这里边最复杂的一个,就是说在单台服务器上进行垂直拆分以及分区以后,还是不能满足一个数据量的一个支持,包括查询速度。那么这个时候就要进行水平拆分。那么水平拆分呢比如说 比如说一天有两千万的这个订单,这两千万个订单呢,我们需要存放到两个不同的MySQL服务器里面,就是一个MySQL服务器里面存一半,这样的话我们就需要有一个算法,比如说像我们的这个一致性哈希算法,将这个不同的订单分配到这个不同的系统里边。这个时候就用日期就不行了,就是需要按整个业务需求了。因为就是有可能哈,在极端的情况下,是需要查询很多订单的,那么不同的订单在不同的MySQL里边,那么我一个查询可能需要查询多个MySQL,所以这个时候就需要去考虑用哪个键值去划分它的一个水平拆分key,这样的话才能够避免单个SQL查询多张表的这样一个情况。
基本上MySQL这一片的话我觉得基本上是到头了。
那么还有一个就是终极的这个MySQL调优,那么就是我们的一个冷热备份。嗯就是基本上就是说对于这个无用数据,他首先会占用一个比较大的内存,比较大的这个硬盘,嗯这种情况下就是根据这个业务需求没有问题的话,可以将这个数据进行一个实时的备份,那么这样呢就能保证我们的这个MySQL的真正的一个总体的存储量达到一个稳定的状态。
基本上这就是这几年来我对于MySQL调优的经验