Mysql复习计划(一)- 字符集、文件系统和SQL执行流程

  • 前言
  • 一. Mysql字符集
    • 1.1 Mysql5.7和8.0的默认字符集
      • 1.1.1 修改默认的字符集
      • 1.1.2 修改已有库表的字符集
    • 1.2 Mysql各级别的字符集
      • 1.2.1 字符集比较规则
      • 1.2.2 字符集从请求到响应的变化过程
    • 1.3 Mysql大小写规范
  • 二. Mysql文件系统和权限
    • 2.1 查看数据库
    • 2.2 用户管理和权限
      • 2.2.1 Mysql访问控制
  • 三. Mysql执行流程
    • 3.1 查询缓存
      • 3.1.1 静态表
    • 3.2 解析器解析
    • 3.3 优化器解析
    • 3.4 执行器
    • 3.5 查询缓存的使用案例

前言

在Docker中,安装两个版本的Mysql,一个5.7的,一个8.0的,因为我的虚机上已经安装了5.7的。因此这里再用Docker安装下8.0的。

用Docker安装Mysql8.0
1.首先先看下Docker基本的命令,看下Docker中有哪些镜像:

docker images

结果如下:

2.安装8.0版本的Mysql:格式:docker pull [镜像名称]:[版本]

docker pull mysql:8.0

3.用该镜像启动一个容器:

sudo docker run -p 3306:3306 --name mysql8.0 \
-v /mydata/mysql8.0/log:/var/log/mysql \
-v /mydata/mysql8.0/data:/var/lib/mysql \
-v /mydata/mysql8.0/conf:/etc/mysql \
-v /mydata/lig/mysql-files:/var/lib/mysql-files \
-e MYSQL_ROOT_PASSWORD=你的Mysql密码 \
-d mysql:8.0

4.查看容器是否启动成功:

docker ps

结果如下:

注意:
安装Mysql8.0和5.7有个细微的区别,若启动的时候指定了外部配置存储,需要比Mysql5.7多一个配置,否则会报错。

-v /mydata/lig/mysql-files:/var/lib/mysql-files \

一. Mysql字符集

在mysql8.0开始,数据库的默认字符集改为了utf8。而Mysql5.7这类的默认字符集都是latin1

1.1 Mysql5.7和8.0的默认字符集

查看字符集命令:

 show VARIABLES like '%character%'

结果如图:

在Mysql8.0中创建表并查看:

create DATABASE dbtest1;
use dbtest1;create table user(id int,name varchar(20));insert into user(id,name) values(1,'Tom');
insert into user(id,name) values(1,'林家俊');select * from user;

结果如下:

倘若我在Mysql5.7版本中再重复一遍上述的过程,看看结果发生了报错

因为我们此时添加了中文数据,但是呢,我们表和数据库使用的字符集是latin1,是不支持中文的。 比如查看字符集:

show create DATABASE dbtest1

结果如下:

1.1.1 修改默认的字符集

因为我的Mysql使用的是外部配置映射,根据上述的配置信息(Mysql8.0和5.7的配置路径是一样的,只不过机器不一样),前往/mydata/mysql/conf,添加my.cnf文件:

[mysqld]
character_set_server=utf8

然后重启mysql: docker restart mysql,此时我们再看下字符集

可以发现,我们的默认字符集已经改成了utf8但是我们已经创建的表和数据库的字符集是不能够被顺带修改的。在今后新创建的表或者数据库的时候,才会应用这个配置。 例如我们此时创建个新的数据库dbtest2

create DATABASE dbtest2;
use dbtest2;create table user(id int,name varchar(20));insert into user(id,name) values(1,'Tom');
insert into user(id,name) values(1,'林家俊');select * from user;

结果如下,能够正常创建:

1.1.2 修改已有库表的字符集

use dbtest1;
# 修改数据库的字符集
ALTER DATABASE dbtest1 character set 'utf8';
# 修改表的字符集
ALTER TABLE user convert to CHARACTER set 'utf8';

1.2 Mysql各级别的字符集

Mysql字符集的级别分为4种:层级关系由上到下递增。

  • 服务器级别(修改后也决定数据库的级别)。
  • 数据库级别。
  • 表级别。
  • 列级别。

服务器级别字符集设置,一般我们通过配置文件来进行,例如:

[mysqld]
character_set_server=utf8

数据库级别字符集设置,具体语法如:

create database [数据库名] character set [字符集名称];
alter database [数据库名] character set [字符集名称];

表级别字符集设置,具体语法如:

create table [表名] character set [字符集名称];
alter table  [表名] character set [字符集名称];

列级别字符集设置,具体语法如:

create table [表名]([列名] [字符串类型] [character set xxx],...,
);

1.2.1 字符集比较规则

utf8utf8mb4的区别:(我们可以发现Mysql8.0默认字符集为utf8mb4

  • utf8:表示一个字符需要使用1~4个字节表示字符。
  • utf8mb3:缩略版的utf8字符集,只使用1~3个字节表示字符。
  • utf8mb4:正宗的utf8字符集。使用1~4个字节表示字符。

注意:Mysql中utf8utf8mb3的别名。若有需求去存储4字节编码一个字符的情况,例如emoji表情,那就需要设置字符集为utf8mb4.

证明:show CHARSET

我们可以发现第三列Default collation,代表字符集的默认比较规则。

后缀 描述
_ai 不区分重音
_as 区分重音
_ci 不区分大小写
_cs 区分大小写
_bin 以二进制方式比较

重要的几个点:

  • utf8_general_ciutf8_unicode_ci对于中英文来说没有什么实质区别。
  • utf8_general_ci相对而言速度快,但是准确度较差。
  • utf8_unicode_ci准确度高,但是速度较慢。并且适用于多语言的比较。

查看和修改表的比较规则:

show table status from dbtest1 like '%user';ALTER table user DEFAULT CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

1.2.2 字符集从请求到响应的变化过程

我们先来看下3种字符集的系统变量:

  • character_set_client:服务器解码的时候使用的字符集。
  • character_set_connection:服务器处理请求的时候会将character_set_client字符集转化为character_set_connection字符集。(相当于传输过程中的一个中间态)
  • character_set_results:服务器向客户端返回数据的时候使用的字符集。

流程如下:

从流程当中我们可以注意以下几点:

  1. 客户端使用的字符集和character_set_clientcharacter_set_results字符集必须三者一致。不然进行请求的时候,服务器可能无法识别对应的字符。
  2. 客户端使用的字符集和character_set_results不一致,会导致客户端无法解码。也就是所谓的乱码现象(本质原因了)。
  3. 所以一般开发过程中,三者一般都设置为统一的字符集,当然,如果是Mysql8.0,默认的都是utf8mb4

1.3 Mysql大小写规范

大家可以用该命令进行查看:

show VARIABLES like '%lower_case_table_names%'

结果如下:

该值有以下三种:

  • 0:大小写敏感。
  • 1:大小写不敏感,创建的表,数据库都是以小写的形式存放在磁盘上。对于sql语句,都是将其转化为小写来进行查找的。
  • 2:创建的表和数据库依据sql语句上的格式来存放,但是查找的话都是根据小写来进行。

Mysql对于linux和window环境下的大小写规范区别如下:

  • 数据库名、表名、表的别名、变量名严格区分大小写。
  • 关键字、函数名在SQL中不区分大小写。
  • 列名、列的别名在所有情况下忽略大小写。

二. Mysql文件系统和权限

我们知道,Mysql的存储引擎我们较为熟知的有InnoDB与MyISAM。这样的存储引擎都是将表存储在磁盘上的。我们将操作系统用来管理磁盘的结构称之为文件系统。

2.1 查看数据库

这个命令也比较简单:

show DATABASES;


其中有4个数据库是Mysql创建的时候就自带的系统数据库:

  • mysql:核心数据库,存储了Mysql的用户和权限信息、存储过程、事件的定义等。
  • information_schema保存着Mysql服务器维护的其他数据库的信息,例如有哪些表、视图、触发器、索引等等。
  • performance_schema保存Mysql服务器运行过程中的状态信息,一般用于监控Mysql的各类性能指标,比如最近执行了哪些语句。执行过程花了多少时间等。
  • sys:主要通过视图的方式把information_schema数据库和performance_schema数据库结合起来。

以本篇文章创建的dbtest1数据库为例,我们去/mydata/mysql/data/dbtest1目录下去查看数据(我这里做了外部文件映射,不然就是/var/lib/mysql/data/

  • db.opt:存储了dbtest1这个数据库的一些基本信息,如使用的字符集、比较规则等。
  • user.frm:存储了user这张表的表结构。
  • user.ibd:存放user这张表中的数据(独立表空间)。

当然,Mysql还有个系统表空间用来存储表数据的:

注意:

  • 默认情况下,InnoDB会在数据目录下创建一个名为ibdata1、大小为12M的文件。
  • 在Mysql5.6后,默认就会为每个表建立一个独立的表空间,也就是所谓的xxx.ibd文件。
  • 我们可以自己指定使用系统表空间还是独立表空间。
[server]
# 0:系统表空间,1:独立表空间
innodb_file_per_table=0

小结下就是:若表使用InnoDB存储引擎,一张表会产生1~2个文件:

  • xxx.frm:描述表结构文件。
  • 若采用系统表空间模式,数据和索引信息存储在ibdata1文件中。
  • 若采用独立表空间模式,则产生xxx.idb文件用于存储数据和索引信息。
  • 在Mysql8.0中,不再单独提供xxx.frm文件,而是将其整合到xxx.idb文件中了。

若采用MyISAM存储引擎:一张表会产生3种文件

  • Mysql5.7中:xxx.frm文件。Mysql8.0中:xxx.sdi文件。两者都是用来描述表结构和字段长度的。
  • xxx.MYD文件:数据信息文件。
  • xxx.MYI文件:存储索引信息文件。

在Mysql8.0和5.7中分别创建表:

use dbtest1;CREATE TABLE `student` (`id` bigint(20) DEFAULT NULL,`name` varchar(64) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Mysql5.7中的文件类型:

Mysql8.0中的文件类型:

2.2 用户管理和权限

Mysql的登录命令如下:

mysql -h hostname -p port -u username -p databaseName -e "SQL语句"

用户的权限查看:

show PRIVILEGES;

授予权限原则:

  1. 只授予能够满足需要的最小权限
  2. 创建用户的时候限制用户的登录主机,一般指定IP。
  3. 为每个用户设置有一定复杂度的密码
  4. 定期清理不需要的用户

授权命令:

grant [权限1],[权限2] on [数据库名称 | *].[表名 | *] to [用户名]@[用户地址]

例如:
我在Mysql8.0中创建一个用户

create user 'ljj' IDENTIFIED by '000000';
# 赋予这个用户对数据库dbtest1下的student表,查询和插入的权限
GRANT SELECT ,INSERT on dbtest1.student to 'ljj'@'%';

此时我用ljj用户来访问Docker中的Mysql:

1.先查看对应容器的id: docker ps

2.复制对应的容器id,执行命令:docker exec -it [你的容器id] bash,进入容器内部。
3.连接Mysql客户端:mysql -u ljj --p[密码]
4.测试权限:

use dbtest1;
INSERT into student(id,name) VALUE(1,'3');
SELECT * from student;
UPDATE student SET name ='3' WHERE id = 1;

然后发现报错:

倘若某个用户被删除,那么我们需要回收对应的权限,命令如下:

revoke [权限1],[权限2] on [数据库名称 | *].[表名 | *] from [用户名]@[用户地址]

2.2.1 Mysql访问控制

用户在操作Mysql的时候,Mysql首先会核实该用户对应的操作请求是否被允许,而这个过程叫做访问控制过程。分为两个阶段:

  1. 连接核实阶段。
  2. 请求核实阶段。

连接核实阶段:

  1. 客户端用户在连接请求的时候,会提供用户名、主机地址、密码等信息。
  2. Mysql服务器接收到用户的请求,使用user表中的host、user、authentication_string这三个字段来匹配客户端提供的信息。
  3. 只有三者都匹配,服务器才接受连接。若连接核实阶段不通过,服务器就会拒绝访问。 此时进入下一个阶段。

请求核实阶段:

  1. Mysql首先检查user表,若指定的权限没有在user表中被授予,此时检查db表。
  2. db表中的权限限制于数据库层级。该层级中的SELECT权限允许用户查看置顶数据库的所有表数据。
  3. db表中依旧没有找到权限,则检查tables_priv表以及columns_priv表。
  4. 若以上表都没找到对应权限,则返回错误信息,用户请求无法执行。操作失败。

三. Mysql执行流程

流程图如下:

3.1 查询缓存

客户端发送一个请求的时候,Mysql会先去缓存中去寻找这条SQL语句。

  • 若缓存查询中有,则直接将结果返回给客户端。
  • 若缓存中没有,那么进入下一个阶段解析器阶段。

值得注意的是:查询缓存的效率并不高,因此Mysql8.0之后抛弃了这个功能。

缓存的形式:Key-Value

  • Key:执行过的语句。
  • Value:对应语句的结果、

那么为什么查询缓存的效率不高呢?原因有三点:

第一点:只有相同的查询操作才会命中查询缓存。若两个查询请求有任何字符上的不同(空格、字符、大小写等),都会导致缓存不会命中,因此Mysql的查询缓存命中率并不高。

例如:

select * from user;
# 这里多了几个空格,那么这两个查询语句作为key明显不一样,长度都不一样
select    * from user;

第二点:若查询请求中包含某些系统函数、用户自定义变量和函数或者查询系统表。那么该请求不会被缓存。

例如函数NOW每次调用都会产生不同的结果,那么这样的SQL语句是不会被加入到查询缓存当中的。


第三点:缓存有失效时间,Mysql的缓存系统会涉及到每张表。但是只要该表的结构或者数据被修改(Insert、Update、Delete)等操作,那么该表相关的高速缓存查询都会置为无效并从缓存中删除。

因此对于更新操作频繁的数据库来说, 查询缓存的命中率低的不行。

那么什么样的情况适合使用查询缓存呢?

3.1.1 静态表

如果我们有一些表,基本上不会涉及到更新,比如系统配置表、字典表等。那么我们可以在这张表的查询上使用查询缓存。

如何开启?在my.cnf配置文件中添加:

query_cache_type=2

query_cache_type有3个值:

  • 0:代表关闭查询缓存。
  • 1:代表开启。
  • 2:DEMAND,只有sql语句中有SQL_CACHE关键词的时候才缓存。

例如我希望对以下SQL进行缓存:

select SQL_CACHE * from config where id = 3;

查看当前数据库是否使用查询缓存:

show VARIABLES like '%query_cache_type%'

结果如下:

监控查询缓存的命中情况:

show status like '%Qcache%'

结果如下:

Qcache_free_blocks:空闲的block数量,数值越大,代表缓存中的碎片越多。
Qcache_free_memory:缓存大小。
Qcache_lowmem_prunes:有多少条缓存是因为内存不够而命中不到。若值比较大,说明需要增加查询缓存的内存大小。
Qcache_not_cached:表示因为query_cache_type参数的设置而没有命中查询缓存的次数。
Qcache_hits:表示有多少次命中缓存。数字越大,效果越理想。
Qcache_inserts:表示多少次未命中缓存然后将结果插入到缓存中的情况。

在查询缓存阶段结束后,就该进入解析器解析阶段了。

3.2 解析器解析

这一阶段,Mysql的目的是需要知道传入的SQL语句是要做什么事情,因此需要对其做词法、语法的分析。

词法分析中:

  1. 比如分析select关键字,那么此时该SQL是一条查询语句。
  2. 将字符串xxx识别成表名xxx,找到对应的表。
  3. id的识别等。

语法分析中:

  1. 主要是根据语法规则,判断输入的这个SQL语句是否满足Mysql的语法。

倘若SQL语句正确,那么此时会生成一个语法树:

3.3 优化器解析

该阶段主要是是确定SQL语句的执行方式, 比如:是全表搜索,还是索引检索。

一条查询语句可以有很多种执行方式,最后都返回相同的结果,而优化器的作用就是找到最优的执行方案。

例如:

  1. 一张表中有多个索引,优化器决定使用哪个索引。
  2. 一个语句中有多表关联join的时候,优化器决定各个表的连接顺序。
  3. 表达式优化。子查询转为连接等。

而优化又分为两个阶段:

  1. 逻辑查询优化:通过索引和表连接等方式来优化。
  2. 物理查询优化:通过SQL等价变化来提升查询效率,即用最优的SQL写法来替代。

3.4 执行器

到这里为止,Mysql服务器已经有了一个执行计划,准备交给执行器来执行。

本阶段主要是调用存储引擎的API对表进行读写操作(在有权限的前提下)

总结下执行流程就是:

  1. SQL语句。
  2. 分析器进行语法分析和语义检查。生成对应的语法分析树。
  3. 此时进入优化器,进行逻辑和物理优化。生成查询计划。
  4. 交给执行器来执行。
  5. 生成查询结果。

3.5 查询缓存的使用案例

此时我们如果打开Mysql5.7的查询缓存功能(8.0该功能已抛弃),在配置文件my.cnf中添加属性:

query_cache_type=1

然后重启docker:

docker restart mysql

此时在查看查询缓存的启用情况:

确认profiling是否开启,开启它后可以让Mysql手机在SQL执行时所使用的资源情况。

SELECT @@profiling;

若你的值为0,代表关闭,可以使用命令将其临时开启:

同时在设置以下profiling

# 这种设置方式是临时的
set @@profiling=1;

同样我们执行两边相同的SQL语句,例如:

 select name from user where id =1

然后查看SQL执行过程:

show PROFILES;

结果如下:

此时我们查看下详情

# 默认是最近的一次查询
show PROFILE;
# 指定查询语句ID查看过程
show PROFILE for query 4;

第一次查询:

第二次查询:

我们可以发现:

  1. 第一次查询,最后将查询结果加入到了查询缓存中。
  2. 第二次查询,查询结果是直接从查询缓存中返回的。

Mysql复习计划(一)- 字符集、文件系统和SQL执行流程相关推荐

  1. beeline执行sql文件_MyBatis的SQL执行流程不清楚?看完这一篇就够了

    前言 MyBatis可能很多人都一直在用,但是MyBatis的SQL执行流程可能并不是所有人都清楚了,那么既然进来了,通读本文你将收获如下: 1.Mapper接口和映射文件是如何进行绑定的 2.MyB ...

  2. Mysql复习计划(四)- 索引失效和数据库设计规范

    Mysql复习计划(四)- 索引失效和数据库设计规范 一. 索引失效 1.1 数据准备 1.2 最左匹配原则 1.3 计算.函数.类型转换导致索引失效 1.4 范围条件右侧的列索引失效 1.5 不等于 ...

  3. Linux基础知识--2.Linux的文件系统和bash的基础特性(1)

    Linux基础知识--linux的文件系统和bash的基础特性 一.Linux文件系统: Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux ...

  4. 一幅长文细学华为MRS大数据开发(二)——HDFS分布式文件系统和ZooKeeper

    文章目录 2 HDFS分布式文件系统和ZooKeeper 2.1 HDFS概述以及应用场景 HDFS概述 HDFS应用场景 HDFS不适合的场景 2.2 HDFS相关概念 计算机集群结构 基本系统架构 ...

  5. Linux和DOS文件系统的区别,对比Linux文件系统和DOS文件系统

    对比Linux文件系统和DOS文件系统 二 盖 氢拿 对比 文件系统和 娄 秦皇岛职业技术学院 文件系统 雨 河北 秦皇岛 [摘 ,. 共]件系统是操作系统用以表明磁盘或分区上的文件的一种方法以及数据 ...

  6. 谷歌技术“三宝”之一的Google文件系统和Kosmos 文件系统

    转:http://www.cppblog.com/jack-wang/archive/2010/02/26/108503.aspx 谷歌技术"三宝"之一的Google文件系统和Ko ...

  7. mysql执行sql流程_MySQL架构与SQL执行流程

    MySQL架构设计 下面是一张MySQL的架构图: 上方各个组件的含义如下: Connectors 指的是不同语言中与SQL的交互 Management Serveices & Utiliti ...

  8. MySQL系列---架构与SQL执行流程详解

    文章目录 1. 背景 2. 架构体系 2.1 架构图 2.2 模块详解 2.3 架构分层 3. 查询SQL语句执行流程 3.1 连接 3.1.1 MySQL支持的通信协议 3.1.2 通信方式 3.2 ...

  9. mysql 8.0 一条insert语句的具体执行流程分析(二)

    继续上一篇文章:mysql 8.0 一条insert语句的具体执行流程分析(一)_一缕阳光的博客-CSDN博客 由于最近换工作一直在试用期内,在拼命的学习.总结中,因此没有时间写文章,今天转正了腾出来 ...

最新文章

  1. pta两个有序链表的合并_21. 合并两个有序链表
  2. datagenerator解决训练时候内存不足问题
  3. html5指南针源码,《绝秘奉献》——最新超短线指南针!源码已放!(贴图 原码)...
  4. 宇宙总统(洛谷-P1781)
  5. Matlab如何实现区间优化
  6. 事业编和公务员哪个好?
  7. virtualbox报错:Failed, trying without DKMS的解决方案
  8. 论文解读——An Analysis of Scale Invariance in Object Detection – SNIP
  9. 移动前端开发与web前端开发的区别
  10. python+selenium自动截取政府官网及失信公示平台搜索结果图
  11. 1. VCS仿真原理——当我们谈论simv时,我们在谈论什么
  12. win7音量图标不见了怎么办捏
  13. OpenCV 表盘指针自动读数
  14. 基于Electron的桌面端应用开发和实践
  15. 针对文档加密系统,如何不破解将文档解密上传
  16. MVC框架运行流程和目录结构
  17. php和android和mysql_如何使用JSON连接Android和PHP Mysql数据库
  18. 【MOS】如何利用RMAN可传输表空间迁移数据库到不同字节序的平台(文档 ID 1983639.1)...
  19. 十六进制转十进制(栈实现)
  20. CodeLite IDE for windows (一)安装及HelloWorld

热门文章

  1. 世界坐标系,相机坐标系,平面坐标系,像素坐标系
  2. WIFI室内定位系统设计与实现(小学期满分项目)
  3. SenseTime Ace Coder Challenge 暨 商汤在线编程挑战赛* B. 我觉得海星 bitset
  4. Linux九阴真经之九阴白骨爪残卷5(ansible用法二之Playbook和YAML语法)
  5. 单片机解密: (数分钟搞定)
  6. 大葱炒鸡蛋_百度百科
  7. java中草药美白淡斑紧肤膏_中医:美白5种药材+美白淡斑3个偏方
  8. batstat oracle_oracle语句批处理
  9. architecture
  10. 数据中心运营商OneAsia宣布与APG建立战略合作伙伴关系