mysql运行的整体架构简介
Mysql是由两部分构成,一部分是服务器程序,一部分是客户端程序。
服务器程序又包括两部分:
第一部分server层包括连接器、查询缓存、分析器、优化器、执行器等。涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等
第二部分是存储引擎层负责数据的存储和提取。存储引擎有多种选择,主要有InnoDB、MyISAM、Memory等。
要操作Mysql数据库,首先客户端要连接上mysql服务器程序。
连接器: 负责跟客户端建立连接、获取权限、维持和管理连接。
连接命令:
mysql -h$ip -P$port -u$user -p
MySQL采用的TCP/IP协议进行网络通信,客户端和服务端之间通过三次握手建立连接。
连接上数据库后,就可以执行sql语句了(以查询语句为例)。
sql查询语句命中缓存
查询缓存: 当sql是查询语句,MySQL 拿到这个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。这个查询请求能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。查询缓存前要校验用户对表是否有查询权限。
查询缓存往往弊大于利:
查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空,对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。
通过设置参数 query_cache_type,选择是否使用查询缓存。
mysql8.0已经将查询缓存的整块功能删掉了。
没有命中查询缓存,就要开始真正执行语句了
分析器: 分析器会做“词法分析”和“语法分析”以及“语义分析等,判断sql语句中的关键字,表,语法是否正确。
如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒,语法错误会提示第一个出现错误的位置,所以你要关注的是紧接“use near”,可以很方便检查sql语句。
优化器: 语法解析之后,服务器程序获得到了需要的信息,比如要查询的列是哪些,表是哪个,搜索条件是什么等等。但光有这些是不够的,因为我们写的MySQL语句执行起来效率可能并不是很高,MySQL的优化程序会对我们的语句做一些优化,如外连接转换为内连接、表达式简化、子查询转为连接等。可以通过expllian语句来查看某个sql语句的执行计划。
执行器: MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。先是校验权限,要先判断一下你对这个表 T 有没有执行查询的权限,然后根据表的引擎定义,去使用这个引擎提供的接口。
存储引擎: 储存数据,并提供读写接口。
存储引擎的一些操作:
查看当前服务器程序支持的存储引擎:
SHOW ENGINES;
设置表的存储引擎
-- 创建表时指定存储引擎
CREATE TABLE 表名(
建表语句;
) ENGINE = 存储引擎名称;
-- 修改表的存储引擎
ALTER TABLE 表名 ENGINE = 存储引擎名称;
查看表使用的存储引擎
SHOW CREATE TABLE 表名
字符集和比较规则
字符集:表示字符的范围以及编码规则,字符编码规则是指一种映射规则,根据这个映射规则可以将某个字符映射成其他形式的数据以便在计算机中存储和传输。例如ASCII字符编码规定使用单字节中低位的7个比特去编码所有的字符,在这个编码规则下字母A的编号是65(ASCII码),用单字节表示就是0x41,因此写入存储设备的时候就是二进制的 01000001。
以下是ASCLL字符编码规则以及字符范围(128个)。
一些重要的字符集
GB2312字符集
收录了汉字以及拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母。
其中收录汉字6763个,其他文字符号682个。
同时这种字符集又兼容ASCII字符集,所以在编码方式上显得有些奇怪:
-如果该字符在ASCII字符集中,则采用1字节编码。否则采用2字节编码。
GBK字符集
GBK字符集只是在收录字符范围上对GB2312字符集作了扩充,编码方式上兼容GB2312。
utf8字符集
收录地球上能想到的所有字符,而且还在不断扩充。
这种字符集兼容ASCII字符集,采用变长编码方式,编码一个字符需要使用1~4个字节
MySQL中支持的字符集
查看当前MySQL中支持的字符集
SHOW CHARSET;
MySQL中的utf8和utf8mb4区别
utf8mb3:阉割过的utf8字符集,只使用1~3个字节表示字符。
utf8mb4(mysql 5.5.3版本之后):正宗的utf8字符集,使用1~4个字节表示字符。
某些中文生僻字或者emoji表情,是四个字符的,只能使用utf8mb4编码
字符集的比较规则:既比较两个字符大小的规则,每种字符集对应若干种比较规则,每种字符集都有一种默认的比较规则。例如:不区分大小写,按照中文拼音顺序等。
查看MySQL中支持的比较规则的命令
SHOW COLLATION
MySQL有4个级别的字符集和比较规则
- 服务器级别
- 数据库级别
- 表级别
- 列级别
服务器级别
-- 查看Mysql服务器的字符集
SHOW VARIABLES LIKE 'character_set_server';
-- 查看Mysql服务器的比较规则
SHOW VARIABLES LIKE 'collation_server';
-- 修复服务器的字符集和比较规则
-- 可以在启动服务器程序时通过启动选项
-- 或者在服务器程序运行过程中使用SET语句修改这两个变量的值。
[server]
character_set_server=gbk
collation_server=gbk_chinese_ci
数据库级别
-- 查看数据库的字符集
SHOW VARIABLES LIKE 'character_set_database';
-- 查看数据库的比较规则
SHOW VARIABLES LIKE 'collation_database';
-- 创建数据库时指定字符集和比较规则
CREATE DATABASE 数据库名
[[DEFAULT] CHARACTER SET 字符集名称]
[[DEFAULT] COLLATE 比较规则名称];
-- 修改数据库指定字符集和比较规则
ALTER DATABASE 数据库名
[[DEFAULT] CHARACTER SET 字符集名称]
[[DEFAULT] COLLATE 比较规则名称];
表级别
-- 查看表的字符集
show create table <表名>;
-- 查看表的比较规则
show table status from 数据库名 like '%表名%‘ ;
-- 创建表时指定字符集和比较规则
CREATE TABLE 表名 (列的信息)
[[DEFAULT] CHARACTER SET 字符集名称]
[[DEFAULT] COLLATE 比较规则名称]]
-- 修改表指定字符集和比较规则
ALTER TABLE 表名
[[DEFAULT] CHARACTER SET 字符集名称]
[[DEFAULT] COLLATE 比较规则名称]
列级别
-- 查看列的字符集和比较规则
select *
FROM information_schema.`COLUMNS`
where TABLE_SCHEMA = '表名'
-- 创建表时指定列的字符集和比较规则
CREATE TABLE 表名(
列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称],
其他列...
);
-- 修改列指定字符集和比较规则
ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称];
在转换列的字符集时需要注意,如果转换前列中存储的数据不能用转换后的字符集进行表示,就会发生错误。比方说原先列使用的字符集是utf8,列中存储了一些汉字,现在把列的字符集转换为ascii的话就会出错,因为ascii字符集并不能表示汉字字符。
创建时规则:
- 如果创建或修改列时,没有显式的指定字符集和比较规则,则该列默认用表的字符集和比较规则
- 如果创建或修改表时,没有显式的指定字符集和比较规则,则该表默认用数据库的字符集和比较规则
- 如果创建或修改数据库时,没有显式的指定字符集和比较规则,则该数据库默认用服务器的字符集和比较规则
修改时规则:
- 只修改字符集,则比较规则将变为修改后的字符集默认的比较规则。
- 修改比较规则,则字符集将变为修改后的比较规则对应的字符集。
客户端和服务器通信中的字符集
-
客户端使用操作系统的字符集编码请求字符串,向服务器发送的是经过编码的一个字节串。
-
服务器将客户端发送来的字节串采用character_set_client代表的字符集进行解码,将解码后的字符串再按照character_set_connection代表的字符集进行编码。
-
如果character_set_connection代表的字符集和具体操作的列使用的字符集一致,则直接进行相应操作,否则的话需要将请求中的字符串从character_set_connection代表的字符集转换为具体操作的列使用的字符集之后再进行操作。
-
将从某个列获取到的字节串从该列使用的字符集转换为character_set_results代表的字符集后发送到客户端。
-
客户端使用操作系统的字符集解析收到的结果集字节串。
我们通常都把 character_set_client 、character_set_connection*、character_set_results*** 这三个系统变量设置成和客户端使用的字符集一致的情况,这样减少了很多无谓的字符集转换
InnoDB记录结构
Mysql默认使用InnoDB作为存储引擎的数据存储结构,我们最常用到的存储引擎也是Innodb,故要了解的是使用InnoDB作为存储引擎的数据存储结构。
数据页简介
InnoDB是一个将表中的数据存储到磁盘上的存储引擎,所以即使关机后重启我们的数据还是存在的。而真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上。而我们知道读写磁盘的速度非常慢,和内存读写差了几个数量级,所以当我们想从表中获取某些记录时,InnoDB存储引擎需要一条一条的把记录从磁盘上读出来么?不,那样会慢死,InnoDB采取的方式是:将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB中页的大小一般为 16 KB。也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。
行记录、页结构、区概念、段概念、独立表空间和系统表空间
行记录
在mysql中,行记录是数据存储的基本单位,我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式。InnoDB存储引擎有四种行格式,分别是Compact(紧凑的)、Redundant(冗余的)、Dynamic(动态的)和Compressed(压缩的)。虽有不同,但原理相同。
创建或修改表的语句中指定行格式
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称
ALTER TABLE 表名 ROW_FORMAT=行格式名称
查看当前表指定的行格式
show table status from lottery like '%表名%' ;
Compact(紧凑的)行格式
一条完整的记录其实可以被分为记录的额外信息和记录的真实数据两大部分
记录的额外信息
变长字段长度列表
存放所有变长字段的真实数据占用的字节长度,每个可变长字段的对应的长度按照列的顺序逆序存放;
变长字段中存储多少字节的数据是不固定的,故需要记录变长字段的真实数据占用的字节长度。
变长字段类型包括VARCHAR(M)、VARBINARY(M)、各种TEXT类型,各种BLOB类型等。
NULL值列表
用于标识表中允许存储NULL的列,是否为空。也是按照列的顺序逆序排列
记录头信息
由固定的5个字节组成
记录的真实数据