数据库系统复习

数据库的复习。主要用的书籍是《MySQL技术内幕InnoDB存储引擎》第二版。

体系结构和存储引擎

数据库和实例

这点非常重要,后续的一些概念会用到,所以这里着重区分一下这俩。

数据库:本质上是文件的集合。这些文件保存的位置可以通过select @@datadir;查看。大概如下图所示(部分)

image-20200709111916739

实例:数据库实例就是真正用于操作数据库文件的。而且实例在操作系统的表现上,就是一个进程。所以我们和数据库之间进行通信,用的就是进程之间的通信方式。

体系结构

image-20200709112219090

自底向上可以看到,首先是文件系统,因为mysql本身就是把数据和索引放到文件系统中的。接下来是各种各样的存储系统,当然我们这里以InnoDB为主。再上去就是mysql的一些优化器执行器等。这里注意,不同的存储引擎,针对的是,而不是数据库。

存储引擎

反正日常中真的是基本只使用InnoDB,所以其他的我觉得就算了。InnoDB它支持事务,支持MVCC,支持行级锁,支持聚簇索引,支持外键。代价就是它的存储文件非常之大

连接mysql

之前说了mysql数据库实例是一个进程,所以可以通过进程间通信的方法,来连接数据库实例。

  1. TCP/IP套接字。用的最多的就是它,可以跨设备进行通信。当你使用mysql命令指定主机的时候,用的就是这种方式。
  2. 命名管道和共享内存。在同一台windows机器上,可以使用命名管道和共享内存的方式进行连接,但是我没有使用过。至于为什么是在Windows上支持而linux不支持,找了博客说的理由是,linux上已经有域套接字这种更好的方法了,所以不需要命名管道和共享内存的方法。
  3. Unix域套接字。linux上使用,只能本机使用,相比起socket,速度快。默认连接本机的mysql用的就是这个方法。

InnoDB存储引擎

再次说一下它的特点:支持行锁,支持MVCC,支持外键,提供一致性非锁定读,同时设计用来最有效的利用CPU和内存。

InnoDB体系架构

image-20200709123055224

简单来说就是有很多个内存块,这些内存块组成了内存池(上图的内存池)内存池负责维护数据结构,并且能够缓存磁盘上的数据,对redo log进行缓冲等。

InnoDB的线程

可以发现InnoDB使用的是多线程模型,有不同的线程来完成不同的工作:

  • master thread:将缓冲池中的数据异步刷新到磁盘
  • io thread:为了提高性能,InnoDB是用的是AIO的方式来处理写IO请求的,而这个线程主要就是负责IO请求的回调。下图中可以看到有4个读和4个写回调的线程(如果你CPU核心多,可以调大这些数值)。读线程的ID总是小于写线程的。

image-20200709123630063

  • purge thread:清除线程的意思,当事务提交之后,undolog就已经完成它的一部分使命了(别的事务可能使用MVCC在使用,所以不能马上删除),那么就用这个线程来回收undolog所使用的页。
  • page cleaner thread:脏页的刷新操作专门交给这个线程来完成。

InnoDB的内存

数据库的文件都是保存在磁盘中的(使用NDB存储引擎的除外)。简单来说就是利用了内存作为了缓冲,第一次读取的时候从磁盘读取,读完之后还会把页放入到缓冲区,这样下次使用可以直接读取内存中的页而不是磁盘中的。同样如果对数据进行了修改,那么先修改缓冲区的页,然后以一定频率再写回到磁盘中。而且读取的命中率高达99%以上。

image-20200709124437668

可以看到我这台使用了134M的内存空间。那么具体的缓冲池缓冲的页,有哪些呢?

image-20200709124612224

大部分都被数据页和索引页给占据了,但是还有少部分是插入缓冲等信息。同时还可以使用多个缓冲池(图中只有一个缓冲池,红框框起来的),然后页会使用哈希算法给平均分配给各个缓冲池中。

在innodb中,缓冲池页的大小默认是16K,默认使用LRU进行缓冲池中的数据也和索引页的管理(只有数据页部分和索引页使用LRU),但是它这个lru不是直接把最新的数据放到链表头部,而是放到链表的某一个位置,由midpoint指定,然后在这个midpoint前面的就是最新的数据,而后面的就是老一些的数据了。这么做的理由是,如果你进行全部的扫描,那么每个页如果都放到头部,反而会把真正的热点数据给顶掉了。所以需要先把页插入到中间的位置,如果这个页真的是热点数据,再放到头部去。

除了LRU这个列表之外,还有一个flush列表,在其中的页表示的是数据已经脏掉了,需要重写回磁盘中。

从上图还可以看到红框外有一个叫重做日志缓冲的区域,用来将重做日志先放到这里,然后再写到重做日志的文件中去,所以这块空间不用很大,绝大部分只需要8M即可。

还剩下最后的一块空间是额外内存池,应该是用来存放LRU,锁这些信息的。

checkpoint

缓冲就是为了能够提高效率,带来的问题也很明显:修改数据只是先到内存,然后再找机会写回到磁盘中。但是如果还没写回磁盘,系统挂了,那岂不是数据就不正确了吗?innodb使用了write ahead log策略,就是我先写好重做日志,然后再去修改页。这样可以通过事后重做来进行补救。

innodb有两种checkpoint,分别是:

  • sharp checkpoint:数据库关闭,把所有脏页都写回到磁盘
  • fuzzy checkpoint:每隔一定时间,从脏页列表中刷新一定比例的页回磁盘;LRU尾端移除的页如果是脏页,那么就需要写回磁盘;重做日志文件不可用的时候,需要将页强制刷新到磁盘中;脏页太多了也需要触发,保证内存缓冲区有足够的可用的页。

master thread

该线程每秒执行的任务:

  • 一定把日志缓冲刷新到磁盘中,就算这个事务没提交。所以就算特别大的事务,提交的时间也是极短的。
  • 可能会合并插入缓冲。这个并不一定每秒发生,如果innodb判断当前IO压力小,就可以执行。
  • 可能会刷新脏页到磁盘。这个也并不一定每秒发生。

该线程每10秒执行的任务:

  • 可能会刷新100个脏页到磁盘。我个人挺好奇为什么是指定数量的。
  • 一定合并插入缓冲。
  • 一定将日志刷新到磁盘中。
  • 一定删除无用的undo页。
  • 一定刷新100个或者10个脏页到磁盘。是不是似乎和第一个矛盾了?

关键特性

  • 插入缓冲
  • 两次写
  • 自适应哈希索引
  • 异步IO
  • 刷新邻接页

插入缓冲

主键是行的唯一标识,而行记录的插入顺序就是按照主键递增的顺序,也就是聚集索引是顺序的,不需要磁盘随机读取。(也有少部分主键用类似UUID的,这样就不是顺序的了)

而除了主键外,我们还会在别的列上定义辅助索引(secondary index),然后在插入的时候,由于是按照主键插入到页里的,但是在非聚集索引里,需要花时间去找到应该放到哪个位置。innodb则是使用了insert buffer,如果插入的非聚集索引页在缓冲池中,那么可以直接插入;否则就先放到insert buffer中,等过一会一起操作,这样提高性能。当然这么做的前提有两点:1.索引是辅助索引 2. 索引不是唯一的(唯一的相当于对于每一条行,你都肯定要花时间去B+树里找)

举个例子就是,你是一个司机,需要把乘客从A运到B,但是你为了多赚一点,肯定希望有两个乘客,它们都想去B,那么你就只需要运一趟就可以了。

当然除了插入缓冲,还可以有更新缓冲和删除缓冲,道理都是一样的。

实现方式是使用一棵所有表格都共享的B+树,非叶子节点放的是表的id,页的偏移量(合在一起称search key)。当辅助索引要插入到页里面的时候,如果该页不在缓冲池中,那么首先构造好search key,然后查询B+树,把记录插入到子节点中。

两次写

假如正在把页写回去的时候,正好宕机了,那么可能会出现只写了部分数据进去。可能会说,那我用重做日志可以恢复呀。重做日志记录的是修改,所以我们首先需要一个页的副本,然后通过在这个页的副本上面进行重做,才能还原真正的结果。所以解决方法就是在写入到磁盘上面之前,还去保存一份副本就可以了。

自适应哈希索引

如果对索引页建立哈希索引能够带来速度提升,那么就建立。此过程无需人为干预。

异步IO

这个就不说了。值得注意的是Macos不支持操作系统的原生AIO。

刷新邻接页

当脏页刷新到磁盘时,会检查当前脏页的所在区的所有页,如果有就一起刷了,这样可以把多个IO合并成一个IO操作。

文件

参数文件

mysql在启动的时候需要读取配置文件,配置文件的顺序可以使用mysql --help | grep my.cnf来查看配置文件的位置,而且后一个配置文件会覆盖掉前一个配置文件相同的配置项。

参数本身分为动态参数和静态参数,静态参数只要实例启动了就不能进行更改,动态参数则会根据会话范围或者是实例范围来生效。

日志文件

日志可以分为错误日志(error log)、二进制日志(binlog)、慢查询日志(slow query log)和查询日志(log),这些日志都默认存放在datadir下面,可以通过show global variables like 'datadir';查看

错误日志

当数据库遇到问题的时候应该首先查看这个。在数据库中可以使用show variables like 'log_error';来查看错误日志文件的位置。

慢查询日志

简单来说就是可以通过设置一个阈值,当一句SQL的时间超过了这个阈值的时候,就会记录到慢查询日志中去。这个阈值可以通过show variables like 'long_query_time';进行查看,默认是10秒。

还有一个参数是如果你查询没有用到索引,那就把这条查询语句放入到慢查询日志中去,通过show variables like 'log_queries_not_using_indexes';,默认是关闭的。当然如果打开了这个选项,而每次查询又都不使用索引,那么这个日志文件会很大,所以可以指定每分钟最多纪录多少次。

日志文件的地址可以通过show global variables like '%slow%';查看。由于这个日志文件一般会比较庞大,所以有一个mysqldumpslow的命令可以帮助你更好分析这个日志文件。

查询日志

纪录所有对MySQL数据库请求的信息,不论是否成功。

二进制日志

对于数据库执行更改的所有操作。该值日主要是为了能够对数据库进行恢复,当然也能够进行数据库的复制和审计。

这个日志是用二进制记录的,所以直接用cat等命令进行查看会乱码,需要用mysqlbinlog命令进行查看。

套接字文件

在Unix下,连接本地的mysql可以使用Unix域套接字方式,这个文件的位置可以通过show variables like 'socket';查看,然后就可以通过mysql -S /var/run/mysqld/mysqld.sock进行登录了。

pid文件

通过show variables like 'pid_file';可以找到这个文件,这个文件里的数字就是当前MySQL的进程ID号。

表结构定义文件

每个表都有对应的文件,不论你采用什么存储引擎,都会有个.frm的表格来记录表格的结构定义。当然直接用cat来查看肯定是不行的。

存储引擎文件

从这部分开始就是innodb专属的了。

表空间文件

innoDB将数据部分按照表空间进行存放。默认有一个叫ibdata1的文件,它就是默认的表空间文件。可以把所有的表的数据都存放在一个文件中,也可以对每个表格分开存放数据,通过show variables like 'innodb_file_per_table';参数可以得知。这里需要注意的是,单独的表空间文件仅存储该表的数据、索引和插入缓冲BITMAP等信息,其余信息还是放在默认的表空间中。

image-20200709220757505

重做日志文件

在innodb的数据目录下会有两个文件:ib_logfile0和ib_logfile1的文件,它们就是redo log file。一个innodb至少有一个重做日志文件组,一个组下面至少有2个重做文件,就是上面的那两个。这两个文件大小相同,并且通过循环写入的方式运行:即先写到文件0中,写满了就写到1中,1写满了又去写0.

image-20200709221225981

那么重做日志和之前的二进制日志有什么区别呢?二进制日志并不针对某个存储引擎,而重做日志针对的是innodb。二进制记录的是逻辑的内容,比如执行了一条update命令,而重做日志记录的是每个页的更改情况,是一种物理情况。最后二进制日志文件在事务提交前进行提交,只会往磁盘里写一次,而事务执行过程中,会不断有日志被写入到重做日志中去(具体是先放到内存的缓冲中,然后再写到磁盘)。

索引组织表

在innodb中,表都是按照主键顺序进行组织存放的,称之为索引组织表。一个表如果没有手动指定,那么会选择第一个(不是你建表的顺序,而是你建立索引的顺序)非空且唯一的索引,如果还是没有,则innodb会自动创建一个6字节大小的指针。

逻辑存储

所有的数据被逻辑放到表空间中,然后表空间又可以分成段(segment)、区(extent)、页(page)。

image-20200709223958425

表空间

如果启用了每张表单独一个文件,那么数据索引和插入缓冲bitmap页放到单独的文件中,但是回滚信息,插入缓冲索引页,系统事务信息都还是放到公共的文件中去。

从上面的图的左上角可以看到每个表空间都是分成一段一段的,常见的段有数据段、索引段和回滚段。

区,是由连续的页组成的,上图中的右下角就是一个区的示意图,且一个区保证是1MB大小(64个page,每个page16KB),为了连续性,innodb会一次性申请4~5个区。

但是如果每个表都用到至少一个区,而一个区大小一定是1MB,那就有点浪费了,所以在申请之前,会先用32个页大小的碎片页来存放数据。

页是innodb中,磁盘管理的最小单位,每个页是16KB,可以进行设置。

每个页最多存放7992行数据。

InnoDB行记录格式

通过show table status like '具体的表名';可以查看表中的行记录的格式。

compact行记录格式

字面意思是紧凑型的。那显然如果一个页能够存放更多的行,就可以有效减少页的读取,提升数据库的性能。而compact的格式如下图所示:

image-20200709232129126

  • 变长字段长度列表用来指示列的长度(就是如果一个列的长度不一定,就用这个值,最典型的就是varchar了),如果小于255字节,用1字节表示;如果大于255字节,用2字节表示,所以最大也就是65535。而且注意这个是逆序存放的,也就是如果列1长度是3字节,列2长度是2字节,这个头部的字段会是02 03。

  • 接下来是null标志位,如果这一行数据里面有null值,则置为1。长度是固定的1字节。假设第二列和第三列是Null,那么这个字节转化成二进制就是:0000 0110,所以在mysql中,null是不消耗空间的。

  • 然后是定长5字节的记录头信息。记录了这一条记录有多少条记录,记录的类型和下一条记录的相对位置。

  • 接下来就是用户的数据了。其中null是不占用任何空间的,然后还有两个隐藏列,分别是事务ID列回滚指针列,如果没有定义主键,那么还会有一个6字节的rowid列,所以非常推荐有主键。

redundant行记录格式

image-20200710001444443

  • 第一个字段和之前有一点点区别,分别是每一列数据的偏移量。假设第一列是01,然后第二列长度是02,那么就应该是03 01(03 = 02 + 01),而且需要倒序。
  • 记录头里面有一项信息比较重要,就是这一行一共有多少列。由于这项信息最多是10比特,所以一行中最多1023列。

对于varchar类型的null值,redundant是不会消耗空间的,而char则需要消耗空间。

看到这里有个疑问,只记录变长的列的长度,那我是怎么知道定长的列的长度的呢?查表结构吗?

行溢出

一页的大小是16KB,而一行最大的可以到65535字节,显然远远超过了页,那是通过什么方法放进去的呢。

所以遇到列太大的问题,innodb的做法是,保存一部分前缀,然后将剩余的部分放到溢出页中。

compressed和dynamic行记录格式

之前说到如果某一列数据太大,那么会保留一部分前缀,剩余部分放到溢出页中。而这俩的做法是,全部放到溢出页中,在数据页里面只留下一个20字节的指针。同时还支持压缩算法。

char和varchar

在使用多字节字符集类型的时候,char(n)中的n代表的是字符的长度,假设你用的是gbk,那么char(10)可以放下10个汉字,占据20字节。所以在多字节字符集下,char和varchar在实际行存储中,只有char是需要填充0x20这个区别。

Innodb数据页结构

image-20200710013214024

约束、视图和分区

暂时跳过。

索引和算法

概述

innodb支持B+树索引、全文索引和自适应哈希索引(无法人为干预)。

在使用B+树索引的时候,首先找到被查找的那一行所在的页,把它读入到内存里,然后在内存中,通过页的page directory结构进行二分查找,但是由于在磁盘中找到页的时间远远大于在内存中的操作时间,所以一般会忽略掉内存中的操作时间。

B+树

B+树是为磁盘设计的一种平衡查找树,所有记录节点都是按照键值的大小存放在同一层叶子节点上,然后叶子节点指针进行连接。

###B+树索引

B+树的高度一般是2-4层,即只需要2-4次IO就可以找到对应的行所在的页。数据库中的B+树索引可以分为聚集索引和辅助索引,它们内部实现都是B+树,区别在于叶子节点存放的是否是一整行数据。

聚集索引

按照表的主键构造一棵B+树,叶子节点中存放的数据就是行数据,所以称叶子节点为数据页。

而在非数据页(就是在非叶子节点上)存放的仅仅是键值以及指向数据页的偏移量。

辅助索引

叶子节点存放的是书签(bookmark)而不是对应的行数据,书签本质上是一个主键的值,所以你查完辅助索引之后,还需要去聚集索引里再从头查一次。

cardinality

对于低选择性的,例如国家字段、性别字段等,是没有必要增加B+树字段的。那么如何判断一个索引是否是具有高选择性的呢?就是靠的cardinality这个值,用来表示索引中不重复记录的预估值。

在Innodb中,该值会在insert操作和update操作的时候,并且满足一定条件的时候才进行更新(毕竟这玩意儿的更新耗费系统资源),而且更新的算法是通过随机采样获得的,所以该值只是一个大概的值。

B+树的使用

联合索引

简单来说就是多个列作为一个索引来使用。并且数据是按照第一列先排好序,在第一列相同的情况下再判断第二列,以此类推。实际例子就是我在商城订单的表中,对用户id和订单时间做了联合索引,这样子查询某个用户的所有订单会快很多(然而由于数据量太小,我是完完全全没有察觉出来有变快)

覆盖索引

从辅助索引中就可以得到查询的记录,不需要再去查询聚集索引的记录。比如有一个表,有列A~列Z,我已经创建了一个联合索引(A,B),那么如果我只是需要查询AB两列的数据,那么只需要到辅助索引去查询一下数据即可,不需要去聚集索引那里再去走一遍。

Multi-Range Read优化

简写为MRR,当你从辅助索引中查出数据之后,需要进行回表,而回表操作是比较乱的,所以这个时候可以根据查出的数据,按照主键来进行一次排序操作,之后就可以较为快速的去聚簇索引里面访问了。

Index Condition Pushdown优化

原来正常的查询,首先根据索引查找记录,然后通过where语句来过滤记录。而使用这个技术就可以在查找记录的同时就把条件给过滤掉了。

哈希算法

虽然内存中的读取速度非常快,但是如果内存庞大,在其中找到某一页还是比较费时的,这个时候就需要哈希算法来帮助了。

哈希索引本质上就是一个hashmap,记录了每张表所在的位置,所以哈希索引对于条件精确的查找效率极高,但是对于范围查找则无能为力。

全文索引

显然如果条件是where content like '%word%',这样的查询用不了索引,没办法就只能去全文检索了。全文检索效率不高,所以针对英文,还是有解决办法的。

倒排索引

核心思想是记录了单词和单词在哪个文档中的映射关系。

具体的说,假设有一张表有两列,一列是ID,还有一列是文本内容,那么就可以构造这么一个倒排索引:

image-20200710125340288

以第一行作为例子,说明单词code在文档1中出现了,具体位置在第6字节;同时在第4个文档也出现了,出现位置在第8字节。

为了提高全文检索的并行性,这样的表格有6张,且按照latin编码进行分区,被持久化保存在磁盘中。还有一个FTS Index Cache用来提高性能,其本身是一个红黑树。和之前的思想一致,如果在对应的表中更新了数据,那么会在这个FTS Index Cache中做对应的修改,之后找时间再同步回磁盘的表格中。

PS:innodb的全文检索是不支持中文的。

全文检索

注意!上面的是全文索引,这部分是全文检索,两者是非常不同的。

emm 书中介绍了全文检索的用法…没有讲原理,我就不赘述了。

innodb存储引擎中的锁

有两种标准的行级锁:共享锁和排它锁。只有共享锁和共享锁之间是兼容的,其它都是互斥的。

意向锁是将锁定的对象分成多个层次,如果需要访问底层的行记录,需要去对表和页加意向锁,其中任何一个环节没得到意向锁就需要等待。具体来说有两种意向锁,分别是意向共享锁和意向排它锁。

一致性非锁定读

如果有一个事务对行进行delete或者update的操作,这时候肯定是加了排它锁,那么innodb不会因为加了排它锁就去等待,而是去读取行的一个快照信息,这就是一致性非锁定读。它的实现就是通过undo段来实现的。一个行记录可能有多个快照,这就是多版本并发控制MVCC。

在read commited 和 repeatable read隔离级别下,用的就是非锁定一致性读,只不过读取的快照数据是不同的。对于read commited读取的是最新的一份快照数据,而对于repeatable read则是读取的是事务开始时候行数据版本。

一致性锁定读

select ... for update加的是一个排它锁,select ... lock in share mode加的是一个共享锁。但是就算加了排它锁,上面的一致性非锁定读还是可以获取到快照信息。

自增长问题

一般来说我们都是让主键进行自增长的,实现起来也很方便,就是用一个计数器。在并发下面由于操作不是原子性的,所以innodb使用的是特殊的表锁机制:事务等待前一个插入语句完成(而不是事务完成)。之后使用了互斥量进行操作,不过没有详细讲述。

锁的算法

行锁的算法

  • record lock:锁定单行
  • gap lock:锁定一个范围,但是不包含记录本身
  • next-key lock:上面两者结合,锁定自己+一个范围,左开右闭。当查询的列是唯一索引的情况下,会降级成record lock

解决幻读

利用next-key lock就可以解决幻读问题。

事务

最简单的事务就是一旦出现问题就回到最原始的状态,而稍微改进一点就是在操作中加入保存点,就像游戏有存档一样。

事务的实现

事务的隔离性,是通过锁来实现的;原子性和持久性通过redo log实现;一致性是通过undo log实现的。

redo

在数据库运行的时候,不需要对redo log文件进行读取操作。只需要确保,在事务提交的时候,将这些操作写入到磁盘的文件中即可。当然如果设置不是每次事务commit都强制写入磁盘可以大大提升效率,但是机器宕机的时候可能会发生最后的那些数据丢失的问题。

二进制日志binlog和重做日志redolog之间的区别:

  • 二进制日志是mysql数据库上层生成的,任何存储引擎对数据库更改都会产生,而重做日志仅仅由innodb生成。
  • 二进制日志是一种逻辑日志,记录了使数据库发生改变的语句。而重做日志是记录的是页的修改。
  • 二进制日志只是在事务提交完成后,一次性写入;重做日志会随着事务的进行而不停写入。

重做日志是通过块的方式保存的,一块的大小是512字节。其中还需要有12字节的头部和8字节的尾部。一个一个的块组合在一起就成了log group。

重做日志还有一个特性,就是它是幂等的,

undo

与redo不同,undo存放在数据库内部的段中,段则位于共享表空间中。而且undo存的是逻辑修改:对于Insert,innodb会使用delete修改回去;对于delete则使用insert修改回去;对于update则使用反向update修改回去。

mvcc也是通过undo日志来完成的。用户读取一行记录,如果这条记录别的事务在使用,那么就可以通过undo来读取之前的信息,实现一致性非锁定读。所以事务完成之后,undolog也不能马上删除,因为可能有别的事务需要读取之前的undo log来实现mvcc,具体的删除交给线程来判断。

最后,undo log也会产生redo log。

分布式事务

在使用分布式事务的时候,隔离级别必须设置成串行化。

外部分布式XA

XA由多个资源管理器,一个事务管理器和一个应用程序组成。

  • 资源管理器RM:通常一个数据库就是一个资源管理器。
  • 事务管理器TM:协调各个事务

image-20200710191428945

简单来说就分成两个阶段,第一阶段TM告知各个RM进行准备,如果所有人都准备好了,那么TM就告知进行提交或者进行回滚;只要有一个RM没有准备好,大家就都需要回滚。

内部XA

在事务提交的时候,希望先写二进制日志,然后再写重做日志。且希望这两个操作是原子的,这主要是为了主从之间的一致性问题。

备份与恢复

跳过。目前用不到。

性能调优

CPU

我个人目前接触到数据库用的比较多的操作就是查询数据,偶尔插入或者修改一两条数据。所以针对我这种用户,显然是IO性能需要强悍一点,CPU可以一般。当然如果CPU是多核的。那么可以通过修改之前提到的写线程和读线程的数量来充分利用CPU的多核性能。

内存

内存当然是越大越好啊,如果大到能把整个数据库都放进去,速度就是美滋滋的了。但是实际中并没有很多钱来买内存,所以需要预估出来活跃的数据有多少,并且根据活跃的数据来分配内存,活跃数据可以通过查看缓存的命中率来看,如果命中率地狱99%,那就需要警惕了。

磁盘

如果是传统的机械硬盘,可以组成RAID来提高性能,或者是通过吧数据文件分布在各个硬盘中来达到负载均衡。

如果用的是固态硬盘,可以增加innodb_io_capacity的值。

RAID

这部分就算了吧。

操作系统

我是一直在linux下使用mysql的