96-mysql-高级篇:
推荐网站
mysql学习网站:https://www.bilibili.com/video/BV1iq4y1u7vj?p=109&vd_source=39a1ba1654411bc9ab90f6f2926600b7
mysql:https://dev.mysql.com/doc/refman/8.0/en/
算法:https://www.cs.usfca.edu/~galles/visualization/about.html
1.MySQL架构篇
1、Linux下MySQL的安装与使用
2、MySQL的数据目录
3、用户与权限管理
4、逻辑架构
1、逻辑架构剖析
1.1 服务器处理客户端请求
MysQL Server结构可以分为如下的三层:
一、连接层
二、服务层
三、引擎层(show engines;)
Connectors: MySQL服务器之外的客户端程序,和具体编程语言相关的内容
Management Service &Utilities–>基础服务组件: MySQL服务器的基础服务组件
Connection Pool -->连接池: 提供了多个用于客户端和服务器端进行交互的线程,这些线程使用完后交还到连接池,供其他客户端使用,从而保证资源不被浪费
SQL Interface–>SQL接口: 作用是用来接收SQL指令并返回查询结果
Parser–>解析器: 用来解析SQL接口中的SQL,分为语法解析和语义解析。解析后会生成一个语法树,该语法树可用于后续的查询优化。解析器将SQL语句“肢解”为关键字、表名、字段名等内容
Optimlzer–>优化器: 核心组件,对SQL进行优化:分为逻辑上的优化和物理上的优化。物理优化—使用索引
Cache & Buffers–>查询缓存: 在8.0中已经弃用。以key - value的方式缓存查询结果,查询结果作为value,SQL语句作为key。当下一次查询和缓存的查询语句完全一致时查询命中
pluggable Storage Engines–>插件式存储引擎: 与底层的文件系统进行交互
File system–>文件系统
File & Logs–>日志文件
2、SQL执行流程
2.1、 MySQL 中的 SQL执行流程
2.2、MySQL的查询流程:
1.查询缓存:SQL完全一样,从缓存查询返回,8.0已经取消。因为命中率太低。
查看当前mysql实例是否开启缓存机制:show variables like ‘%query_cache_type’;
监控查询缓存的命中率:show status like ‘%Qcache%’;
/*Mysql5.7输出
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| query_cache_type | OFF |
+------------------+-------+
Mysql8.0输出:
Empty set (0.01 sec)
*/
2.解析器:对SQL进行语法分析、语义分析。语法不对或者用词不对会报错。正确会生成语法树。解析完进入到优化器。
下面是SQL词法分析的过程步骤:
3、优化器:在优化器中会确定 SQL 语句的执行路径,比如是根据全表检索 ,还是根据索引检索等。以及执行顺序等。
**4、执行器:**以上步骤产生一个执行计划。进入执行器阶段 。判断该用户是否有权限等。
SQL 语句在 MySQL 中的流程是: SQL语句→查询缓存→解析器→优化器→执行器 。
2.3、MySQL8中SQL执行原理
MySQL中对一条 SQL语句的执行时间进行分析。
1.确认profiling 是否开启,查看分析是否计划,0关闭,1开启,set profiling=1;
select @@profiling;
或者
show variables like '%profiling%'
show profiles;
show profile cpu,block io for query 6;
2.4、MySQL5.7中SQL执行原理
(存在缓存直接获取)
1.配置文件中开启查询缓存
在 /etc/my.cnf 中新增一行:query_cache_type=1
2.重启mysql服务:systemctl restart mysqld
3.开启查询执行计划
由于重启过服务,需要重新执行如下指令,开启profiling。set profiling=1;
4.执行语句两次:select * from locations;
5.查看profiles:show profiles for query id1/id2;(id2计划更少,直接从缓存取出)
2.5、Oracle中的SQL执行流程(了解)
Oracle 中采用了共享池来判断 SQL 语句是否存在缓存和执行计划,通过这一步可知道应该采用硬解析还是软解析。
SQL 在 Oracle 中的执行过程:
1.语法检查:检查 SQL 拼写是否正确,如果不正确,Oracle 会报语法错误。
2.语义检查:检查 SQL 中的访问对象是否存在。比如我们在写 SELECT 语句的时候,列名写错了,系统就会提示错误。语法检查和语义检查的作用是保证 SQL 语句没有错误。
3.权限检查:看用户是否具备访问该数据的权限。
4.共享池检查:共享池(Shared Pool)是一块内存池,作用是缓存 SQL 语句和该语句的执行计划。 Oracle 通过检查共享池是否存在 SQL 语句的执行计划,对sql进行hash下运算。判断hash是否存在。来判断进行软解析(有计划),还是硬解析(无计划)。
5.优化器:优化器中就是要进行硬解析,也就是决定怎么做,比如创建解析树,生成执行计划。
6.执行器:当有了解析树和执行计划之后,就知道了 SQL 该怎么被执行,这样就可以在执行器中执行语句了。
共享池是 Oracle 中的术语,包括了库缓存,数据字典缓冲区等。
库缓存区:主要缓存 SQL 语句和执行计划。
数据字典缓冲区: 存储的是 Oracle 中的对象定义,比如表、视图、索引等对象。当对 SQL 语句进行解析的时候,如果需要相关的数据,会从数据字典缓冲区中提取。
你可能会问,如何避免硬解析,尽量使用软解析呢?
在 Oracle 中, 绑定变量是它的一大特色。绑定变量就是在 SQL 语句中使用变量,通过不同的变量取值来改变 SQL 的执行结果。这样做的好处是能提升软解析的可能性 ,不足之处在于可能会导致生成的执行计划不够优化,因此是否需要绑定变量还需要视情况而定。
3、数据库缓冲池(buffer pool)
缓冲池和查询缓存是一个东西吗?不是。
3.1、缓冲池和查询缓存
1、缓冲池(Buffer Pool)
在 InnoDB 存储引擎中,缓冲池都包括了哪些。
在 InnoDB 存储引擎中有一部分数据会放到内存中,缓冲池则占了这部分内存的大部分,它用来存储各种数据的缓存,如下图所示:
缓存池的重要性:
索引和系统数据都存储都以页的形式存储在表空间。表空间只不过是InnoDB对文件系统上的抽象,还是存储在磁盘上。cpu更快。缓冲池消除cpu和磁盘之间的鸿沟。更快。
InnoDB存储引擎在请求时,当需要访问某个页的数据时,就会把完整的页的数据全部加载到内存中,在进行完读写访问之后并不着急把该页对应的内存空间释放掉,而是将其缓存起来,这样将来有请求再次访问该页面时,就可以省去磁盘IO的开销了。
缓存原则:(内存直接访问,热点数据优先加载)
“ 位置 * 频次 ”这个原则,可以帮我们对 I/O 访问效率进行优化。
首先,位置决定效率,提供缓冲池就是为了在内存中可以直接访问数据。
其次,频次决定优先级顺序。因为缓冲池的大小是有限的,比如磁盘有 200G,但是内存只有 16G,缓冲池大小只有 1G,就无法将所有数据都加载到缓冲池里,这时就涉及到优先级顺序,会优先对使用频次高的热数据进行加载 。
缓冲池的预读特性:
了解了缓冲池的作用之后,我们还需要了解缓冲池的另一个特性:预读。
缓冲池的作用就是提升IO效率,而我们进行读取数据的时候存在一个"“局部性原理”,也就是说我们使用了一些数据,大概率还会使用它周周的一些数据,因此采用“预读”的机制提前加载,可以减少未来可能的磁盘I/O操作。
2、查询缓存
5.7中的sql为key,结果为缓存。命中率低。8.0取消。
3.2 、缓冲池如何读取数据
缓冲池管理器会尽量将经常使用的数据保存起来,在数据库进行页面读操作的时候,首先会判断该页面是否在缓冲池中,如果存在就直接读取,如果不存在,就会通过内存或磁盘将页面存放到缓冲池中再进行读取。
缓存在数据库中的结构和作用如下图所示:
如果我们执行 SQL 语句的时候更新了缓存池中的数据,那么这些数据会马上同步到磁盘上吗?
实际上,当我们对数据库中的记录进行修改的时候,首先会修改缓冲池中页里面的记录信息,然后数据库会以一定的频率刷新到磁盘上。注意并不是每次发生更新操作,都会立刻进行磁盘回写。缓冲池会采用一种叫做checkpoint 的机制将数据回写到磁盘上,这样做的好处就是提升了数据库的整体性能。
比如,当缓冲池不够用时,需要释放掉一些不常用的页,此时就可以强行采用checkpoint的方式,将不常用的脏页回写到磁盘上,然后两从缓冲池中将这些页释放掉。这里脏页(dirty page)指的是缓冲池中被修改过的页,与磁盘上的数据页不一致。
3.3、查看/设置缓冲池的大小
如果你使用的是MySQL MyISAM存储引擎,它只缓存索引,不缓存数据,对应的键缓存参数为key_buffer_size,你可以用它进行查看。
如果你使用的是 InnoDB 存储引擎,可以通过查看 innodb_buffer_pool_size 变量来查看缓冲池的大小。命令如下:
show variables like 'innodb_buffer_pool_size';
set global innodb_buffer_pool_size = 268435456;
或者:
[server]
innodb_buffer_pool_size = 268435456
3.4 多个Buffer Pool实例
Buffer Pool本质是InnoDB向操作系统申请的一块连续的内存空间,在多线程环境下,访问Buffer Pool中的数据都需要加锁处理。在Buffer Pool特别大而且多线程并发访问特别高的情况下,单一的Buffer Pool可能会影响请求的处理速度。所以在Buffer Pool特别大的时候,我们可以把它们拆分成若干个小的Buffer Pool,每个Buffer Pool都称为一个实例,它们都是独立的,独立的去中请内存空间,独立的管理各种链表。所以在多线程并发访问时并不会相互影响,从而提高并发处理能力。那每个 Buffer Pool 实例实际占多少内存空间呢?其实使用这个公式算出来的:innodb_buffer_pool_size/innodb_buffer_pool_instances
show variables like 'innodb_buffer_pool_instances';
可以在服务器启动的时候通过设置innodb_buffer_pool_instances的值来修改Buffer Pool实例的个数:
[server]
innodb_buffer_pool_instances = 2
不过也不是说Buffer Pool实例创建的越多越好,分别管理各个Buffer Pool也是需要性能开销的,InnoDB规定:当innodb_buffer_pool_size的值小于1G的时候设置多个实例是无效的,InnoDB会默认把innodb_buffer_pool_instances 的值修改为1。而我们鼓励在Bufer Pool大于或等于1G的时候设置多个Buffer Pool实例。
3.5 引申问题
Buffer Pool是MySQL内存结构中十分核心的一个组成,你可以先把它想象成一个黑盒子。
黑盒下的更新数据流程
当查询数据的时候,会先去Buffer Pool中查询。如果Buffer Pool中不存在,存储引擎会先将数据从磁盘加载到Buffer Pool中,然后将数据返回给客户端;同理,当更新某个数据的时候,如果这个数据不存在于BufferPool,同样会先将数据加载进来,然后修改内存的数据。被修改过的数据会在之后统一刷入磁盘。
这个过程看似没啥问题,实则是有问题的。假设修改Buffer Pool中的数据成功,但是还没来得及将数据刷入磁盘MySQL就挂了怎么办?按照上图的逻辑,此时更新之后的数据只存在于Buffer Pool中,如果此时MySQL宕机了,这部分数据将会永久地丢失;
再者,更新到一半突然发生错误了,想要回滚到更新之前的版本,该怎么办?连数据持久化的保证、事务回滚都做不到还谈什么崩溃恢复?
答案:Redo Log & Undo Log
Redo Log :解决刷盘时刷到一半宕机的问题
Undo Log:解决回滚的问题
5、存储引擎
1. 查看存储引擎
show engines;
# 或
show engines\G
2. 设置系统默认的存储引擎
- 查看默认的存储引擎:
show variables like '%storage_engine%';
#或
SELECT @@default_storage_engine;
- 修改默认的存储引擎
如果在创建表的语句中没有显式指定表的存储引擎的话,那就会默认使用InnoDB
作为表的存储引擎。
SET DEFAULT_STORAGE_ENGINE=MyISAM;
或者修改my.cnf
文件:
default-storage-engine=MyISAM
# 重启服务
systemctl restart mysqld.service
3. 设置表的存储引擎
存储引擎是负责对表中的数据进行提取和写入工作的,我们可以为不同的表设置不同的存储引擎
,也就是说不同的表可以有不同的物理存储结构,不同的提取和写入方式。
3.1 创建表时指定存储引擎
CREATE TABLE 表名(
建表语句;
) ENGINE = 存储引擎名称;
3.2 修改表的存储引擎
ALTER TABLE 表名 ENGINE = 存储引擎名称;
4. 引擎介绍
4.1 InnoDB 引擎:具备外键支持功能的事务存储引擎
- MySQL从3.23.34a开始就包含InnoDB存储引擎。
大于等于5.5之后,默认采用InnoDB引擎
。 - InnoDB是MySQL的
默认事务型引擎
,它被设计用来处理大量的短期(short-lived)事务。可以确保事务的完整提交(Commit)和回滚(Rollback)。 - 除了增加和查询外,还需要更新、删除操作,那么,应优先选择InnoDB存储引擎。
- 除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。
- 数据文件结构:
- 表名.frm 存储表结构(MySQL8.0时,合并在表名.ibd中)
- 表名.ibd 存储数据和索引
- InnoDB是
为处理巨大数据量的最大性能设计
。- 在以前的版本中,字典数据以元数据文件、非事务表等来存储。现在这些元数据文件被删除了。比如:
.frm
,.par
,.trn
,.isl
,.db.opt
等都在MySQL8.0中不存在了。
- 在以前的版本中,字典数据以元数据文件、非事务表等来存储。现在这些元数据文件被删除了。比如:
- 对比MyISAM的存储引擎,
InnoDB写的处理效率差一些
,并且会占用更多的磁盘空间以保存数据和索引。 - MyISAM只缓存索引,不缓存真实数据;InnoDB不仅缓存索引还要缓存真实数据,
对内存要求较高
,而且内存大小对性能有决定性的影响。
4.2 MyISAM 引擎:主要的非事务处理存储引擎
- MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM
不支持事务、行级锁、外键
,有一个毫无疑问的缺陷就是崩溃后无法安全恢复
。 5.5之前默认的存储引擎
- 优势是访问的
速度快
,对事务完整性没有要求或者以SELECT、INSERT为主的应用 - 针对数据统计有额外的常数存储。故而 count(*) 的查询效率很高
- 数据文件结构:
- 表名.frm 存储表结构
- 表名.MYD 存储数据 (MYData)
- 表名.MYI 存储索引 (MYIndex)
- 应用场景:只读应用或者以读为主的业务
4.3 Archive 引擎:用于数据存档
4.4 Blackhole 引擎:丢弃写操作,读操作会返回空内容
4.5 CSV 引擎:存储数据时,以逗号分隔各个数据项
4.6 Memory 引擎:置于内存的表
4.7 Federated 引擎:访问远程表
4.8 Merge引擎:管理多个MyISAM表构成的表集合
4.9 NDB引擎:MySQL集群专用存储引擎
5. MyISAM和InnoDB
对比项 | MyISAM | InnoDB |
---|---|---|
外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁,即使操作一条记录也会锁住整个表,不适合高并发的操作 | 行锁,操作时只锁某一行,不对其它行有影响,适合高并发的操作 |
缓存 | 只缓存索引,不缓存真实数据 | 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响 |
自带系统表使用 | Y | N |
关注点 | 性能:节省资源、消耗少、简单业务 | 事务:并发写、事务、更大资源 |
默认安装 | Y | Y |
默认使用 | N | Y |