MySQL 体系结构详细介绍

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

一、MySQL软件架构

    MySQL体系结构图(逻辑结构)

MySQL 体系结构详细介绍_第1张图片

1、Connectors

指的是不同语言中与MySQL的连接交互层;

2、Management Serveices & Utilities

系统管理和控制工具,例如备份恢复、MySQL复制、集群等;

3、Connection Pool

连接池,管理缓冲用户连接、用户名、密码、权限校验、线程处理等需要缓存的信息;
MySQL服务器对每一个连接产生一个线程,而这个线程独自为该连接服务。因此,MySQL服务器中的并行是指并行执行许多个查询而非一次查询内的并行。也由此原因致使MySQL对多核支持不够好,MySQL服务器是一组线程的集合。

4、SQL Interface

SQL接口,接受用户的SQL命令,并且返回用户需要查询的结果。比如DML就是调用SQL Interface;

5、Parser

解析器,SQL命令传递到解析器的时候会被解析器验证和解析。解析器是由Lex和YACC实现的,是一个很长的脚本;
主要功能: 

  • 将SQL语句分解成数据结构,并将这个结构传递到后续步骤,以后SQL语句的传递和处理就是基于这个结构的;
  • 如果在分解构成中遇到错误,那么就说明这个SQL语句是不合理的 ;
  • Lex:Lexical Analyzer是一种生成扫描器的工具。扫描器是一种识别文本中的词汇模式的程序;
  • Yacc:Yet Another Compiler Compiler是一种工具,将任何一种编程语言的所有语法翻译成针对此种语言的 Yacc 语法解析器;

6、Optimizer

查询优化器,SQL语句在查询之前会使用查询优化器对查询进行优化。他使用的是“选取-投影-联接”策略进行查询;
优化 select uid,name from user where gender = 1; SQL语句执行的过程如下:

  • 这个select 查询先根据where 语句进行记录选取,而不是先将表全部记录查询出来以后再进行gender过滤;
  • 这个select查询先根据uid和name进行属性投影(字段选择),而不是将属性全部取出以后再进行过滤;
  • 将这两个查询条件联接起来生成最终查询结果;

7、Cache&Buffer

高速缓存区,查询缓存,如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。通过LRU算法将数据的冷端溢出,未来得及刷新到磁盘的数据页,叫脏页。这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key缓存,权限缓存等; 

8、Engine

存储引擎,存储引擎是MySQL与文件打交道的子系统。也是MySQL最具有特色的一个地方。MySQL的存储引擎是插件式的,它根据MySQL AB公司提供的文件访问层的一个抽象接口来定制一种文件访问机制(这种访问机制就叫存储引擎)现在有很多种存储引擎,各个存储引擎的优势各不一样。MySQL也支持自定义制存储引擎,甚至一个库中不同的表使用不同的存储引擎,这些都是允许的。

二、数据库与数据库实例

数据库:物理操作系统文件或其他形式文件类型的集合;
数据库实例:数据库后台进程或线程及一个共享内存区域组成,数据库实例是用来操作数据库文件的;
MySQL是一个单进程多线程架构的数据库,与SQL Server类似。Oracle数据库在Linux OS下是多进程,在Windows下也是单进程多线程。MySQL数据库实例在系统上的表现就是一个进程。

三、MySQL常用存储引擎

存储引擎其实就是如何存储数据,如何为存储的数据建立索引以及如何更新、查询数据等技术实现的方法。
MySQL中的数据用各种不同的技术存储在文件(或内存)中,这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平,并且最终提供广泛的不同功能和能力。在MySQL中将这些不同的技术及配套的相关功能称为存储引擎。

1、存储引擎查询

查看MySQL服务器支持的存储引擎及默认的存储引擎。存储引擎是针对数据表的,不是针对数据库的,通过如下命令查看具体表指定的存储引擎。

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
mysql> show variables like '%engine%';
+----------------------------------+--------+
| Variable_name                    | Value  |
+----------------------------------+--------+
| default_storage_engine           | InnoDB |
| default_tmp_storage_engine       | InnoDB |
| disabled_storage_engines         |        |
| internal_tmp_disk_storage_engine | InnoDB |
+----------------------------------+--------+
4 rows in set (0.01 sec)

2、常用存储引擎

MySQL 体系结构详细介绍_第2张图片

Innodb是MySQL数据库5.5版本后的默认存储引擎,默认所说的MySQL即指Innodb存储引擎的MySQL,所以关于Innodb的体系结构专门梳理介绍。

2.1、InnoDB
2.1.1、InnoDB体系结构图

MySQL 体系结构详细介绍_第3张图片

InnoDB是MySQL5.5以后的默认存储引擎,支持事务ACID,回滚,系统崩溃恢复能力及多版本并发控制的事务安全,主要用于OLTP数据库业务场景;支持自增长列(auto_increment);支持外键约束(foreign key);支持MVCC的行级锁;使用Btree索引;
Innodb存储引擎主要包括多个内存池以及后台线程。
内存池:由Buffer Pool包括(undo page、Change buffer page、Adaptive Hash Index、Lock info、data dictionary),Doublewrite Buffer,Additional Memory pool、Redo Log Buffer 组成,主要维护进程/线程的内部数据、缓存磁盘数据,修改文件前先在内存中修改;
MySQL5.7官方文档中关于Innodb存储引擎的体系结构讲解包括
Buffer Pool
Change Buffer
Adaptive Hash Index
Redo Log Buffer
System Tablespace
InnoDB Data Dictionary
Doublewrite Buffer
Undo Logs
File-Per-Table Tablespaces
General Tablespaces
Undo Tablespace
Temporary Tablespace
Redo Log
InnoDB有表空间的概念,包括共享表空间和独立表空间(独立表空间的模式中也要有系统表空间ibdataX,来用于存储内部的数据字典、Undo日志等,通过innodb_file_per_table参数设置启用独立表空间),默认独立表空间模式下会在数据目录下创建tablename.ibd、tablename.frm文件。
InnoDB支持记录Redo文件,记录对所有页面的修改(页面物理结构的变更)操作,可以通过相关的参数进行自定义设置Redo文件存储路径;
InnoDB支持记录Undo文件,记录数据修改前的备份,存储在共享表空间中。用户保证事务的原子性(恢复)和实现MVCC多版本并发控制,辅助完成事务的持久化(Undo信息会持久化)。可通过相关参数进行自定义设置;
更改缓冲(change buffer),基于聚集索引的操作是顺序的,不会造成数据库随机读取,但修改非聚集索引时就会产生大量的随机读写。当修改非聚集索引的数据时,修改操作并非实时更新索引的叶子页,而是把若干对同一页面的更新缓存起来做合并(merge)将一次性更新操作,转化随机IO为顺序IO,这样可以避免随机IO带来性能损耗,提高数据库的写性能。
写两次(double write),(重做日志记录的是页的物理操作,如果页本身损坏,对其重做就没有意义了,在应用重做日志前,需要一个页的副本。先通过页的副本还原该页,再应用重做日志进行恢复)当mysql将脏数据flush到data file的时候,先使用memcopy将脏数据复制到内存中的double write buffer,之后通过double wirte buffer再分2次,每次写入1M到共享表空间,然后马上调用fsync函数,同步到磁盘上;将数据页(page)加载到内存(innodb buffer)->更新数据产生脏页(dirty page)->使用memcopy将脏数据复制到内存中的double write buffer(size=2M)->double wirte buffer再分2次,每次写入1M到共享表空间(ibdata文件)->调用fsync函数,同步到磁盘;使用memcopy将脏数据复制到内存中的double write buffer(size=2M)->double wirte buffer再分2次,每次写入1M到共享表空间(ibdata文件)就是double的过程。
自适应hash索引(adaptive hash index),Innodb会监控表上索引的查找情况,如果通过建立Hash索引能带来性能的提升,则会自动建立hash索引,该过程只能由MySQL Server自行控制,无法人工干预且只适用于等值索引查询;

后台线程:包括(Mater Thread、IO Thread、Lock Monitor Thread、Error Monitor Thread、Purge Thread、Page Cleaner Thread)刷新内存池中的过程数据,管理维护InnoDB存储引擎正常工作;
InnoDB主要的后台线程

MySQL 体系结构详细介绍_第4张图片

Master Thread是一个非常核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括:脏页(dirty page)的刷新、合并插入缓冲(insert buffer merge)、回滚页回收(undo purge)等。innodb_max_dirty_pages_pct脏页刷盘的配置参数,新版默认75,google默认90。

MySQL 体系结构详细介绍_第5张图片

2.1.2、InnoDB表

InnoDB表逻辑结构

  • 表空间:InnoDB存储引擎逻辑结构的最高层
  • 段:组成表空间,数据段,索引段,回滚段等
  • 区:由64个连续的页组成,每个区大小1MB
  • 页:每个页16KB且不能修改,数据页,索引页,系统页等
  • 行:每页最多允许存放7992行数据
  • 行记录格式:常见两种行记录格式Compact和Redundant,MySQL5.1版本后,主要是Compact行记录格式。对于Compact,不管是char型还是varchar型,null型都是不占用存储空间的;对于Redundant,varchar的null不占用空间,char的null型是占用存储空间的。
  • Varchar类型的长度是65535,但实际一般除开其他开销大概65530左右,同时这个限制是一整行数据的长度。
  • create table tbl_varchar(a varchar(22000), b varchar(22000), cvarchar(22000)) charset=latin1 engine=innodb; 因为一行总长大于了65535

数据页结构

  • File Header(文件头):记录页的头信息,固定长度38字节;
  • Page Header(页头):记录页的状态信息,固定长度65字节;
  • Infimum+Supremum Records:两个虚拟的行记录,用于限定记录的边界;
  • User Records:用户记录,实际记录的内容,InnoDB采用B+树索引组织存储表;
  • Free Space:空闲空间,链表数据结构,记录删除后会被加入空闲空间;
  • Page Director:页目录,存放记录的相对位置,B+索引不能找到具体的一条记录,只能找到该记录所在的页,数据库把页载入内存,再通过Page Director查找具体记录行;
  • File Trailer:文件结尾信息,固定长度8字节;

2.2、MyISAM

MyISAM是MySQL5.5之前的默认存储引擎,不支持事务,不支持行级锁,只支持并发插入的表锁,主要用于高负载的查询。
MySQL的系统表大部分都是MyISAM存储引擎的,支持对只读表进行压缩,单压缩后不能对该表进行修改只能查询;
MyISAM按照插入的顺序在磁盘上存储数据,并为每行生成自然顺序行号(row number),从0开始。因为元组的大小固定,所以MyISAM可以很容易的从表的开始位置找到某一字节的位置。
MyISAM不支持聚簇索引,使用Btree索引,但实现细节与InnoDB不同,索引中每一个叶子节点仅仅包含索引字段关键字和行号(row number),且叶子节点按照索引字段关键字的顺序存储,实际上,在MyISAM中,primary key和其它索引没有什么区别。Primary key仅仅只是一个叫做PRIMARY的唯一,非空的索引而已。
创建MyISAM表,MySQL5.7的MyISAM表已经支持text,blob类型了。
mysql> create table tbl_myisam(id int,name varchar(20),describle text,image blob) engine=myisam;
mysql> create table table_myisam_compressed engine=myisam as select * from information_schema.columns;
Query OK, 3132 rows affected (0.23 sec)
Records: 3132  Duplicates: 0  Warnings: 0
MyISAM表默认在数据目录下创建tablename.MYD、tablename.MYI、tablename.frm文件

[root@mysqlnode02 test1212]# ll -h tbl_myisam.*
-rw-r----- 1 mysql mysql 8.5K Dec 12 09:28 tbl_myisam.frm
-rw-r----- 1 mysql mysql    0 Dec 12 09:28 tbl_myisam.MYD
-rw-r----- 1 mysql mysql 1.0K Dec 12 09:28 tbl_myisam.MYI

查看数据表的状态信息,MyISAM表存储格式,三种存储格式(Row_format):静态(Fixed,char)、动态(Dynamic,varchar\blob\text)、压缩(先创建表再通过myisampack工具压缩处理)
mysql> show table status like 'tbl_myisam'\G
MyISAM表容易损坏,可以通过工具进行检查和修复,如果有问题Msg_type里会有warning或error。没有问题的话出现的结果Status是OK。可以使用repair命令修复损坏的MyISAM表,MySQL5.7修复后不生成*.old文件

mysql> check table tbl_myisam;
+---------------------+-------+----------+----------+
| Table               | Op    | Msg_type | Msg_text |
+---------------------+-------+----------+----------+
| test1212.tbl_myisam | check | status   | OK       |
+---------------------+-------+----------+----------+
1 row in set (0.00 sec)

mysql> repair table tbl_myisam;
+---------------------+--------+----------+----------+
| Table               | Op     | Msg_type | Msg_text |
+---------------------+--------+----------+----------+
| test1212.tbl_myisam | repair | status   | OK       |
+---------------------+--------+----------+----------+
1 row in set (0.00 sec)
-- 利用myisampack工具,通过.MYI文件压缩数据文件.MYD
[root@mysqlnode02 test1212]# myisampack  ./myisam.MYI

2.3、Memory

Memory存储引擎的表都是内存表。实际的数据存储在内存中,磁盘中只有表结构定义文件tablename.frm,有利于快速处理,提高整个表的处理能力,重启或关机数据会丢失,可提供极快的访问。Mysql服务单独给memory存储引擎的表分配内存空间,而且表一直持有这些内存空间(即使删除数据也不释放内存),直到有drop、alter、create等重建对象才能释放内存。内存的占用空间由max_heap_table_size参数控制,默认16M,Mysql服务重启后,所有表会自动继承全局的max_heap_table_size参数的值;
创建memory存储引擎表,不支持BLOB/TEXT类型

mysql> create table tbl_memory(id int,name varchar(20),describle text,image blob) engine=memory;
ERROR 1163 (42000): The used table type doesn't support BLOB/TEXT columns
mysql> create table tbl_memory(id int,name varchar(20)) engine=memory;
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like 'max_heap_table_size';
+---------------------+----------+
| Variable_name       | Value    |
+---------------------+----------+
| max_heap_table_size | 16777216 |
+---------------------+----------+
1 row in set (0.01 sec)

默认使用hash索引,对应等值查询效率很高,对应范围查询性能不高;支持Btree索引,如要使用Btree索引需要明确指定创建索引类型;

mysql> create index idx_id on tbl_memory(id);
mysql> create  index idx_name using btree  on tbl_memory(name);
mysql> show index from tbl_memory\G

Memory存储引擎的表只有一个tablename.frm文件

[root@mysqlnode02 test1212]# ll -h tbl_memory.*
-rw-r----- 1 mysql mysql 8.4K Dec 12 09:46 tbl_memory.frm

2.4、CSV

CSV存储引擎是基于CSV格式文件存储数据的。该存储引擎的表将数据以CSV文本方式存储,可以手动直接编辑数据文件,也可通过DML语句操作CSV表,适用于进行小数据量的中间数据交换场景。

-- 创建CSV存储引擎表,要求创建时指定各列非空约束。
mysql> create table tbl_csv(id int,name varchar(30)) engine=csv;
ERROR 1178 (42000): The storage engine for the table doesn't support nullable columns
mysql> create table tbl_csv(id int not null,name varchar(30) not null) engine=csv;
Query OK, 0 rows affected (0.00 sec)
-- CSV存储引擎的表包括.frm是表结构定义文件;.CSV是存放数据文件;.CSM是表状态及表的数据量文件
[root@mysqlnode02 test1212]# ll -h tbl_csv.*
-rw-r----- 1 mysql mysql   35 Dec 12 09:54 tbl_csv.CSM
-rw-r----- 1 mysql mysql    0 Dec 12 09:54 tbl_csv.CSV
-rw-r----- 1 mysql mysql 8.4K Dec 12 09:54 tbl_csv.frm
-- 手动编辑.CSV数据文件,刷新数据表,DML操作数据表
[root@mysqlnode02 test1212]# vi tbl_csv.CSV
[root@mysqlnode02 test1212]# cat tbl_csv.CSV
1,'AAAAA'
2,BBBBB
mysql> flush table tbl_csv;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tbl_csv;
+----+---------+
| id | name    |
+----+---------+
|  1 | 'AAAAA' |
|  2 | BBBBB   |
+----+---------+
2 rows in set (0.00 sec)
mysql> delete from tbl_csv where id=2;
mysql> insert into tbl_csv values (id,'BBBBB');

2.5、BLACKHOLE

支持事务,而且支持mvcc的行级锁,主要用于日志记录或同步归档,这个存储引擎除非有特别目的,否则不适合使用。

2.6、FEDERATED

能够将多个分离的MySQL服务器链接起来,从多个物理服务器创建一个逻辑数据库。十分适合于分布式环境或数据集市环境。

2.7、ARCHIVE

归档(适用于存放大量数据的存储引擎);支持select、insert等操作;不支持delete 、update、索引等操作;使用zlib无损数据压缩算法,节省空间;适用于大量历史数据(可查询但不能删除)的保存。
使用ARCHIVE存储的空间大小是MyISAM存储大小的1/7,大大减少了空间的占用。

mysql> create table tbl_archive engine=archive as select * from information_schema.columns;
Query OK, 3153 rows affected (0.19 sec)
Records: 3153  Duplicates: 0  Warnings: 0
-- .ARZ是数据压缩文件;.frm是表结构定义文件
[root@mysqlnode02 test1212]# ll -h tbl_archive.*
-rw-r----- 1 mysql mysql 30K Dec 12 10:20 tbl_archive.ARZ
-rw-r----- 1 mysql mysql 14K Dec 12 10:20 tbl_archive.frm

四、物理结构(物理文件)

1、参数文件

告诉MySQL实例启动时在哪找到数据库文件,指定某些初始化参数,这些参数定义了某种内存结构的大小等设置。用文件存储,可编辑,加载不到则不能成功启动。参数有动态和静态之分,静态只读,动态可以通过set命令设置。修改时有作用域的区分,通过session或global设置相应的有效域。

# 查看MySQL的参数文件读取顺序
[root@mysqlnode02 data]# mysql --help | grep 'my.cnf'
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf

2、错误日志文件

记录MySQL的启动、运行、关闭过程进行了记录,MySQL使用过程中的错误信息,还记录了一些警告信息以及正确信息,可通过show variables like ‘log_error’查看具体的文件路径。

mysql> show variables like 'log_error';
+---------------+-----------------------------+
| Variable_name | Value                       |
+---------------+-----------------------------+
| log_error     | /mysqldb/errorlog/error.log |
+---------------+-----------------------------+
1 row in set (0.01 sec)

3、慢查询日志文件

记录SQL语句执行较慢的语句,可通过slow_query_log参数控制是否开启,slow_query_log_file参数控制对应的日志文件路径,可通过mysqldumpslow工具查看慢日志。long_query_time参数设置慢查询阀值,等于0记录全部SQL,log_output 参数设置日志记录文件或表中(file/Table)log_queries_not_using_indexes参数设置未使用索引的查询也算慢查询。

4、全查日志文件

记录MySQL的所有请求信息(操作命令),通过general_log,general_log_file两个参数控制开启与路径设置。

5、二进制日志文件

不记录查询,只记录对数据库所有的修改操作,用于恢复和复制。log_bin参数设置是否开启(开启时需要设置server_id),max_binlog_size 设置二进制日志的大小,64MB比较合适,log_bin_basename参数设置二进制日志文件的路径和名称前缀,binlog_format参数设置日志格式(statement,row,mixed)三种格式,可通过mysqlbinlog工具查看二进制日志文件内容。

6、Socket文件

当用UNIX套接字方式进行连接时需要指定的文件。修改了socket文件的目录时,通过MySQL客户端工具连接MySQL时需要-S指定socket文件。socket参数设置文件的存储目录和文件名,可以在my.cnf的[client]下增加socket配置后不用每次都指定。
[client]
socket = /MySQLdb/sockandpid/MySQL.sock

7、pid文件

MySQL实例的进程文件,MySQL实例启动的时候,会将自己的进程id写入一个文件中,pid_file参数设置pid文件的路径和名称,rpm默认安装后会放在默认目录中,重新初始化时需要在my.cnf文件中具体配置(自定义设置的路径不起作用/var/run/mysqld/mysqld.pid)。
[root@mysqlnode02 data]# cat /var/run/mysqld/mysqld.pid
1403

8、表结构文件

存放MySQL表结构定义的文件,每个表都有一个.frm后缀的文件,存放在datadir对应的数据库目录里。

9、数据文件

存储数据的文件,每个存储引擎的数据文件后缀有一定的差异,MyISAM的数据文件是.MYD,InnoDB的数据文件是.ibd或.ibdata*。

10、索引文件

存储索引的文件,每个存储引擎的索引文件后缀会有一定的差异,MyISAM的索引文件是.MYI,InnoDB的索引文件存储在.ibd文件中。

11、Innodb特有的文件

11.1、表空间文件

默认的表空间文件是%datadir%/ibdata1为统一表空间文件,可以通过innodb_file_per_table参数设单独表空间文件,存储各表对应的数据、索引、插入缓存等信息,其余信息还是存放在默认的表空间.ibdata1中;

11.2、Redo日志文件

记录innodb存储引擎对应数据所在的页的更改物理情况,用于保证实例或介质失败后的数据完整性恢复,先与数据持久化,innodb_log_file_size参数设置redo文件的大小,innodb_log_files_in_group参数设置redo文件组的文件数量,innodb_log_group_home_dir参数设置redo文件的路径,ib_logfile*。
二进制日志与重做日志区别
5bc60f51b2f11c33457667f11499f813420.jpg

11.3、Undo日志文件

存在于共享表空间ibdata1里面,有一个回滚段地址,里面存放了头信息,配置头信息,段的头信息,里面存储了与redo相反的数据更新操作,如果rollback的话,就把undo段里面数据回写到数据文件里面。undo log用来完成事务的回滚以及MVCC的功能

五、MySQL内存结构

MySQL内存分配规则是,用多少给多少,最高到配置的值,不是立即分配;MySQL中内存大致分为全局内存(Global buffer)、线程内存(Thread buffer)两大部分。

1、Global Buffer

innodb_buffer_pool_size(IBP)
InnoDB高速缓存data page和index page,是对InnoDB引擎影响最大的参数,建议设置为内存的50%-80%;合并插入缓存也是其中的一部分;
通过show global status like 'innodb_buffer_pool_%'\G;查看IBP的状态,单位是page(16kb),如果Innodb_buffer_pool_wait_free较大需要增加IBP;
通过show status like 'innodb_data_read%';查询的值计算IBP的各种效率,Innodb_data_read总共读入的字节数,Innodb_data_reads发起请求的次数,每次读取可能需要读取多个页;
IBP利用率:(1-Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests)*100%,Innodb_buffer_pool_reads(从物理磁盘读取的页数)Innodb_buffer_pool_read_requests(从缓冲池中读取的页数);
IBP命中率:Innodb_buffer_pool_read_requests/(Innodb_buffer_pool_read_
requests+Innodb_buffer_pool_reads+Innodb_buffer_pool_read_ahead);
平均每次读取的字节数:Innodb_data_read/Innodb_data_reads
innodb_log_buffer_size
InnoDB redo日志缓冲区,提高redo写入效率,如果show global status like '%Innodb%'\G;查出Innodb_log_waits大于0则需要增加该区域大小;
query_cache_size
查询高速缓冲,缓存结果,减少硬解析,建议关闭,通过专业的缓存redis等处理;

2、Thread Buffer

每个连接到MySQL服务器的线程都需要自己的缓冲,连接时大概会立即分配256k,甚至在现场空闲时他们使用默认的线程堆栈网络缓存等。当需要进行复杂操作时会给分配相应的内存空间,操作完成后即释放。
read_buffer_size:对表进行顺序扫描的请求分配的读入缓冲区;
read_rnd_buffer_size:对表进行任意行读取时分配随机读缓存区;
sort_buffer_size:对查询数据进行排序使用的缓存大小;
join_buffer_size:减少参与join的“被驱动表”的读取次数以提高性能,当空间不足时会分批在join_buffer中进行;
binlog_cache_size:二进制日志缓存大小,提高二进制日志写入效率,可以通过如下状态信息查看Binlog_cache_disk_use,Binlog_cache_use;
thread_cache_size:默认是9需要根据业务进行比较的修改,如1024;

六、MySQL查询执行过程

MySQL 体系结构详细介绍_第6张图片

查询缓存,判断sql语句是否完全匹配,再判断是否有权限,两个判断为假则到解析器解析语句,为真则提取数据结果返回给用户;
解析器解析。解析器先词法分析,语法分析,检查错误比如引号有没闭合等,然后生成解析树;
预处理。预处理解决解析器无法决解的语义,如检查表和列是否存在,别名是否有错,生成新的解析树;
优化器做大量的优化操作;
生成执行计划;
查询执行引擎,负责调度存储引擎获取相应数据;
返回结果

七、MVCC机制

MVCC是一种多版本并发控制机制,行级锁对系统的开销较大,通过保存数据在某个时间点的快照来实现MVCC可以替代行锁,降低系统并发控制的开销。
一致性的非锁定读:InnoDB存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行Delete、update操作,这时读取操作不会因此而会等待行上锁的释放,相反,InnoDB存储引擎会去读取行的一个快照数据。快照数据是指该行之前版本的数据,该实现是通过Undo段来实现。而Undo用来事务中回滚数据,因此快照本身是没有额外开销的。此外,快照数据是不需要上锁的,因为没有必要对历史的数据进行修改。一个行可能有不止一个快照数据,所以称这种技术为行多版本技术。由此带来并发控制,称之为多版本并发控制(Multi VersionConcurrency Control, MVCC)。

1、InnoDB的MVCC

MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能,MVCC是通过保存数据在某个时间点的快照来实现的。
读锁,S锁,若当前事务T对数据对象A加S锁,则T可以读取A,其他事务可以对A加S锁,但T和其他事务都不能修改A;
写锁,X锁,若当前事务T对数据对象A加X锁,则T可以读也可以修改A,其他事务不能对A加任何锁(即不能读取或修改A);
表锁,操作对象是数据表,若当前事务T对表A加读锁,其他事务可读不可写;若加写锁,其他事务增删改都不行;
行级锁,操作对象是数据表中的一行数据,行级锁是MySQL存储引擎实现的,不是MySQL服务器实现的,行级锁开销大,但并发性好。
InnoDB的MVCC主要是为Repeatable-Read事务隔离级别做的,简单的理解InnoDB是通过在每行记录后面保存两个隐藏的列来实现MVCC,这两个列分别保存了这个行的创建时间和删除时间(系统版本号,也可以理解为事务的ID),每开始一个事务,系统版本号会自动增加。通过这两时间(系统版本号),在不同的事务隔离级别下操作相应的数据行。
Select:只会检索创建时间版本早于当前系统版本号的数据行(系统版本号小于或等于当前事务对应的系统版本号)且行的删除版本要么未定义,要么大于当前版本号;
Insert:InnoDB会为每个新增的行(创建时间)记录当前系统版本号;
Delete:InnoDB会为每个删除的行(删除时间)记录当前系统版本号;
Update:InnoDB会为新增的一行数据的(创建时间)记录当前系统版本号,同时也会把被修改的数据行的(删除时间)记录当前系统版本号;
MVCC应有的特点,每行数据都存在一个版本,每次数据更新时都更新的该版本;修改是copy当前版本随意修改,各事务之间无干扰;保存时比较版本号,如果成功(commit),则覆盖原记录,失败则放弃copy(rollback)。
InnoDB的实现方式,事务以排他锁的方式修改原数据;把修改前的数据放入Undo log通过回滚指针与主数据关联;修改成功则(commit),失败则利用undo log(rollback)。具体执行过程:begin->用排他锁锁定该行->记录redo log->记录undo log->修改当前行的值,写事务编号,回滚指针指向undo log中的修改前的行->end。
mvcc中update步骤:
记录事务中修改行数据的相应字段和值(包括旧版本事务id)在undo-log中记录;
修改相应数据;
在redo-log中保存要修改的相应(新版本事务id)数据写入;
假如update不能正常运行则根据undo-log redo-log 来恢复;
当然如果当前版本事务没有commit的话则通过undo-log信息恢复原始数据状态。
所以InnoDB的实现真算不上MVCC,因为并没有实现核心的多版本并存,undo log中的内容只是串行化的结果,记录了多个事务的过程,不属于多版本共存。MVCC是通过版本号比对进行事务的提交或回滚,类似于通过乐观锁替代两阶段提交,两阶段提交是保证多行数据修改一致性的唯一手段,其本职是锁定;乐观锁本质是消除锁定,二者矛盾,所以理想的MVCC难以实现实际应用,InnoDB只是在Repeatable-Read事务隔离级别下实现的一种非阻塞读而已。
InnoDB的MVCC是行锁的一个补充,主要实现了“Repeatable-Read”模式下的非锁定读(读非阻塞)。
在Read Committed和Repeatable Read下,InnoDB存储引擎使用非锁定一致性读。然而,对于快照的定义却不同。在Read Committed事务隔离级别下,对于快照数据,非锁定一致性读总是读取被锁定行的最新一份快照数据。在Repeatable事务隔离级别下,对于快照数据,非锁定一致性读总是读取事务开始时的行数据版本。

2、mvcc优缺点

优点:在读取数据时,innodb几乎不用获取任何锁,在每个查询通过版本检查,只获取需要的数据版本,提高系统并发度;
缺点:为了实现多版本,innodb必须对每行增加相应字段来存储版本信息,同时需要维护每一行的版本信息,而且在检索行的时候,需要进行版本的比较,因而减低了查询效率;innodb还需要定期清理不再需要的行版本,及时回收空间,这也增加开销;

八、MySQL的事务

1、事务隔离级别

MySQL的事务是存储引擎层实现的,本部分主要讨论事务存储引擎InnoDB相关事务原理。SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
Repeatable Read(可重读)
这是mysql的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
Serializable(可串行化) 
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。serializable完全锁定字段,若一个事务来查询同一份数据就必须等待,直到前一个事务完成并解除锁定为止 。是完整的隔离级别,会锁定对应的数据表格,因而会有效率的问题。
这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新了原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示:

MySQL 体系结构详细介绍_第7张图片

2、InnoDB事务

通过在log buffer中快速记录SQL语句对数据页的修改,并持久化至redo log文件,需要恢复时利用Redo log恢复相应数据;
通过拷贝修改前的数据至undo buffer,并持久化至undo log。rollback时利用undo log还原数据;
通过行级锁,和MVCC机制提高数据库并发能力的同时降低了系统资源开销;
事务的四个特性:原子性、一致性、隔离性、持久性 
隔离性通过锁实现,原子性、一致性、持久性通过数据库的redo和undo来完成。 
重做日志记录了事务的行为,通过redo实现,保证了事务的完整性,但事务有时还需要撤销,这时就需要产生undo。undo和redo正好相反,对于数据库进行修改时,数据库不但会产生redo,而且还会产生一定的undo,即使执行的事务或语句由于某种原因失败了,或者如果用一条rollback语句请求回滚,就可以用这些undo信息将数据回滚到修改之前的样子。

3、InnoDB锁信息查询

在INFORMATION_SCHEMA架构下添加了INNODB_TRX、INNODB_LOCKS、InnoDB_LOCK_WAITS。通过这三张表,可以更简单地监控当前的事务并分析可能存在的锁的问题。
INNODB_TRX由8个字段组成: 
trx_id:InnoDB存储引擎内部唯一的事务ID 
trx_state:当前事务的状态。 
trx_started:事务的开始时间。 
trx_requested_lock_id:等待事务的锁ID。如trx_state的状态为LOCK WAIT,那么该值代表当前的等待之前事务占用锁资源的ID.若trx_state不是LOCK WAIT,则该值为NULL。 
trx_wait_started:事务等待开始的时间。 
trx_weight:事务的权重,反映了一个事务修改和锁住的行数。在InnoDB存储引擎中,当发生死锁需要回滚时,InnoDB存储会选择该值最小的进行回滚。 
trx_mysql_thread_id:Mysql中的线程ID,SHOW PROCESSLIST显示的结果。 
trx_query:事务运行的sql语句。 
通过select * from infomation_schema.INNODB_TRX;可查看 
INNODB_LOCKS表,该表由如下字段组成: 
lock_id:锁的ID。 
lock_trx_id:事务ID。 
lock_mode:锁的模式。 
lock_type:锁的类型,表锁还是行锁。 
lock_table:要加锁的表。 
lock_index:锁的索引。 
lock_space:InnoDB存储引擎表空间的ID号。 
lock_page:被锁住的页的数量。若是表锁,则该值为NULL。 
lock_rec:被锁住的行的数量。若是表锁,则该值为NULL。 
lock_data:被锁住的行的主键值。当是表锁时,该值为NULL。 
通过select * from information_schema.INNODB_LOCK;可查看 
INNODB_LOCK_WAIT由4个字段组成: 
requesting_trx_id:申请锁资源的事务ID。 
requesting_lock_id:申请的锁的ID。 
blocking_trx_id:阻塞的锁的ID。 
通过select * from information_schema.INNODB_LOCK_WAITS;可查看。 

4、锁的算法

Record Lock:单行记录上的锁 
Gap Lock:间隙锁,锁定一个范围,但不包含记录本身 
Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。

5、锁的问题

丢失更新:经典的数据库问题,当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。   
例: 
    事务A和事务B同时修改某行的值, 
     1.事务A将数值改为1并提交 
     2.事务B将数值改为2并提交。 
     这时数据的值为2,事务A所做的更新将会丢失。 
     解决办法:事务并行变串行操作,对更新操作加排他锁。 
脏读:一个事务读到另一个事务未提交的更新数据,即读到脏数据。 
例: 
    1.Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务)        
    2.Mary读取自己的工资 ,发现自己的工资变为了8000,欢天喜地! 
    3.而财务发现操作有误,回滚了事务,Mary的工资又变为了1000, 像这样,Mary记取的工资数8000是一个脏数据。 
    解决办法:脏读只有在事务隔离级别是Read Uncommitted的情况下才会出现,innoDB默认隔离级别是Repeatable Read,所以生产环境下不会出现脏读。

不可重复读:在同一个事务中,多次读取同一数据,返回的结果有所不同。换句话说就是,后续读取可以读到另一个事务已提交的更新数据。相反"可重复读"在同一事务多次读取数据时,能够保证所读数据一样,也就是后续读取不能读到另一事务已提交的更新数据。脏读和不可重复读的主要区别在于,脏读是读到未提交的数据,不可重复读是读到已提交的数据。
例: 
      1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成 
      2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务. 
      3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000 
      解决办法:读到已提交的数据,一般数据库是可接受的,因此事务隔离级别一般设为Read Committed。Mysql InnoDB通过Next-Key Lock算法避免不可重复读,默认隔离级别为Repeatable Read。
幻读,事务中两次读取同一个范围的数据,读到的记录条数不一致。

 

转载于:https://my.oschina.net/peakfang/blog/2240253

你可能感兴趣的:(MySQL 体系结构详细介绍)