Server层:涵盖MySQL大多数的核心功能,以及内置函数如存储过程、触发器、视图等
存储引擎:负责数据的存储和提取
其中Server层可划分为:
连接器: 负责跟客户端建立连接、获取权限、维持和管理连接
mysql -h ip -P port -u name -p password
show processlist; 查看链接 默认八小时的连接时间 wait_timeout控制
长链接:连接成功后,客户端持续有请求,使用同一连接。
短链接:每次执行完很少的几次操作就断开。
推荐使用长连接 —— MySQL占用内存大
查询缓存: 执行查询命令之前,MySQL会先到缓存中查看,如果存在返回k-v,k为查询语句,v为查询结果
如果不存在,继续往下执行,并把结果缓存到内存中
推荐不使用查询缓存,因为查询缓存失效频繁,如果对一个表更新,那么找个表的所有的查询缓存都会被清除
通过设置 query_cache_type=DEMAND 即不使用查询缓存
设置 SQL_CACHE 显式指定
select SQL_CAHCHE * from T where id=1;
分析器: 如果没有命中查询缓存,则需要对SQL语句解析,分析SQL语句语法是否正确
优化器: 经过分析器后,还需要经过优化器优化决定使用那个索引 多表关联的时候 每个表的顺序
执行器: 经过优化器,MySQL开始执行SQL语句
update user set username='张三' where id=1;
简单来说更新流程同上面讲的查询流程,首先经过连接器进行权限验证、登陆操作,然后将涉及到的user表的查询缓存清空,
接着在分析器中分析语法,优化器中决定使用id这个索引,执行器去执行本条命令,然后执行更新。
其中需要主要的是在执行器还需要同InnoDB进行交互,涉及到 两阶段提交 —— 目的是让 redo_log 和 binlog日志文件一致
redo_log 记录操作到此文件中,等待InnoDB空闲时将数据写入磁盘,保证之前提交的数据不会丢失(物理日志) 直白的说就是记录了做了什么
改动
binlog Server层的日志,逻辑日志,记录sql语句的原始逻辑
先写redo_log: 先写redo_log后,如果数据库异常重启了,binlog未写完。由于redo_log能够进行恢复所以数据库中的username值为 张三
但是因为binlog里面没有这个数据,当使用binlog日志来进行恢复的时候就会出现数据不一致的情况。
先写binlog: 当先写了binlog后,数据库异常重启了,由于redo_log没写,所以数据库的username仍是原来的数据,当使用binlog恢复数据时,
多出一个将username更新为 "张三" 的事务,因此数据库又不一致了。
读未提交 -- 别人尚未提交的数据,本事务也能看到
读已提交 -- 别人已经提交的数据,本事务才能看到
可重复读 -- 别人已经提交的数据,本事务不会去读,需要保持数据一致
串行化 -- 读写均会加锁,其他事务无法修改
隔离级别从上到下并发能力越弱,安全性越高
其中数据库最常见问题存在两个脏读幻读不可重复读:
脏读:简单来说就是针对同一数据两次读取不一致,读取到了其他事务未提交的数据。即读未提交数据!!!
幻读:前后读取多数,数据总量不一致。
不可重复读:针对同一数据,前后多次读取,同一数据内容不一致。
区别:
不可重复读:读取了其他事务提交的数据,对于事务而言是非正常的,应使用行锁来限制其他事务的修改(update操作)
幻读:读取了其他事务的数据(insert、delete操作),使用表锁进行数据量确定
在mysql8.0版本中存储表结构和表数据存放在一个文件中,但是在此之前两者是分开存放的。
在数据删除的时候并不是直接删除问题,只是将相关状态位置为可使用,因此数据文件大小是不会通过delete删除数据减小的。(空洞)
可通过创建临时表,将数据读出再写入避免空洞问题,减少数据文件大小。