启停:
重启:systemctl restart mysqld.service
停止:systemctl stop mysqld.service
查看状态:systemctl status mysqld.service
思考:一条mysql的执行语句,经过了哪些流程
1、通信协议:
mysql服务端,暴露了一个3306端口,客户端用什么协议和他连接?
mysql支持多种协议,一般我们都是使用TCP (mysql-connector-java-x.x.xx.jar)
连接方式:可以支持同步和异步
同步通信一般依赖于被调用方,会被阻塞,等待被调用方返回结果
异步和同步相反,异步可以减少阻塞的时间,但是并不能减少sql执行的时间。存在一个问题,并发情 况下,异步会创建大量的连接。可以使用线程池。但是对于异步结果的返回还是不可控。一般我们使用同步的方式
长连接还是短连接:都支持,但是在连接池中一般使用长连接。
show global variables like 'wait_timeout'; -- 非交互式超时时间,如 JDBC 程序 默认8小时
show global variables like 'interactive_timeout'; -- 交互式超时时间,如数据库工具 默认8小时
show variables like 'max_connections'; 最大连接数 默认151
通信方式: 单工 半双工(mysql是半双工,客户端和服务端可以交互,但是不能同时发送) 全双工
2、缓存,mysql默认是携带缓存的,但是缓存默认是关闭的,主要由于缓存的应用场景有限,所有的sql必须完全一样,连标点空格都需要保持相同,当表里数据发生改变,缓存就失效,意义不大,可以交给缓存框架或者ORM框架处理,这部分可以看mybatis的缓存模块涉及。
3、语法解析和预处理
我们输入一条sql,通信问题ok了,缓存不管,后面应该怎么处理呢?是解析。
mysql对于词法的判断,其实是会将一个完整的sql,打散成一个个单词,从哪开始,到哪结束
语法解析,将所有的词,组装到一个解析树内,实现解析校验
sql语句解析完成了,又如何知道我们的表和字段不存在的呢?
对于表和字段等操作,mysql提供了解析器,来实现检查表名列名,别名等语法没办法解析的数据,封装成一个新的解析树。
4、查询优化器
对于一个sql,mysql其实是有很多种执行方法的,但是具体最后选择了哪一种执行方法,还是由查询优化器来决定的。
执行优化器也还是有自己的判断标准的,mysql中使用的是cost(基于开销的优化器),哪个开销小,选哪个。
优化器可以做哪些,简单举个例子:
1、两张表关联查询,以哪张表为基表
2、同时可以使用多个索引,使用哪个索引。
备注:优化器其实也是代码,还是得优先提高sql的质量。
优化器优化后,还是将解析树变化成一个查询执行计划。
查询计划的工具: EXPLAIN select name from user where id=1;
备注: EXPLAIN 也不一定是最终执行的方式
5、存储引擎
获得到了执行计划,那我们的执行计划在哪里运行 mysql的数据是一个什么样的格式? --> 存储引擎
mysql每个表都可以指定不同的存储引擎,并且可以修改 show table status where name = 'user_innodb';
查看数据的存储位置。就在如下目录中:
innodb有frm和ibd两个文件 frm存储表结构信息 ibd存储索引和数据信息(聚集索引和非聚集索引)
myisam 有frm MYD MYI三个文件 frm:存储表结构信息 MYD: myisam data MYI: myisam index
对比一下Innodb和myisam:
myisam是5.5之前的默认的存储引擎 innodb是5.5之后的
innodb默认支持事物(undo.log redo.log 这个后续再介绍),支持行级别的锁,写不阻塞读MVCC 一般数据一致性要求高,使用
myisam只支持表级别锁 (限制了读写的能力,一般也只是用读多写少的场景), insert和select的速度更快
* 大文件导入时,是不是可以先设置为myisam 然后再转换成innodb,黑操作!
6、执行引擎(执行器)
谁使用执行计划去操作存储引擎数据
mysql其实 实现可以替换执行引擎,其本质思想就是多态,调用指定的规范(接口),具体的存储引擎(实现)都可以使用。
mysql的内部模块:
上面是查询的逻辑,一条更新语句是如何查询的
更新语句的基本流程和查询前面是一致的,区别在于,更新语句,拿到了符合条件数据之后的操作是怎么进行处理的?
下面介绍一下基本概念:
1、缓冲池 buffer pool
Innodb的数据上面我们也介绍了,其本质是存在磁盘文件中的,那么交互时速度必然是比较慢的。一般性思维,加载到内存中。
innodb逻辑上的最小单位是页,那么每次加载的页到内存的区域(预读),就是buffer pool。下一次取数据(数据页或者索引页)时,会优先判断在不在buffer页中。修改时,会修改内存中的数据,当buffer pool中数据和磁盘不一致时,这时就叫脏页。会有工作线程会定时同步,这个操作就叫刷脏
满了怎么办?默认大小是128M LRU的淘汰策略(简单来说就是链表,有头和尾,并且划分年轻代和老年代,以解决预读和扫表产生的问题)
mysql的LRU算法:
普通的LRU:移出链表尾部的数据,从链表头插入
mysql改进的LRU:
1、buffer pool 分为了young(5/8)和old(5/3)两个部分
2、数据会在 用户的sql用到了页中的数据,或者mysql猜测你很可能会用到的数据-预读,这两种情况加载到buffer pool
3、数据优先进入old,old满了就会被移出。young区呢? 用户sql使用的页,会被移入young。而预读的数据,没被使用则会一直在old区带着,被清除
问题: 当一次大表扫描,会导致大量数进入young?
解决:mysql有参数控制 innodb_old_blocks_time,需要在old区待满多少秒,且再被用户sql调用时,才会进入young
下面是找的内存结构和磁盘结构图:
内存:
我们可以看到 buffer pool内部主要包含: buffer pool、 change buffer、 Log Buffer 、 adaptive Hash Index
buffer pool 缓存的主要是页信息(数据页 索引页)
当数据不存在buffer pool时,是不是所有的数据,都需要加载进来呢,这样会多一次 io,有没有优化的?
change Buffer(老版本叫insert buffer)当一个数据没有唯一索引,不存在重复数据的情况,更新操作时就不需要加载出来校验唯一性,可以直接在内存中记录操作,不需要这次io。将数据同步到数据页的操作叫merge。什么时候去merge,一般是在访问这个数据页时、后台线程处理、shoutdown 、redo.log 写满时
Log Buffer 用来记录redo log
作用: 主要用来做崩溃恢复,用来实现事务持久性
内部机制:数据存在缓冲区,没有进行刷盘操作时,如果数据库宕机或者重启,会导致数据丢失。 redo log的作用就是,数据写入缓存后,写一下redo log ,记录的不是最终的结果,而是要进行的操作。崩溃恢复时,将redo log数据重新加载到缓冲区。
策略: 0(延时写) 1 2(实时写,延时刷) 默认是1 事务操作实时记录并刷新数据页
疑问:写到日志文件还是一次磁盘io,为什么不直接写到数据页 ? 顺序IO和随机IO 写日志是顺序io,效率高(可以参考Kakfa)
内存和磁盘中间其实还有一层osCache,用来提高效率。
磁盘:
磁盘中主要组成部分是5类表空间
系统表空间(ibdata1):
组成:数据字典(表和索引的元信息) 、双写缓冲区 、undo log、Change buffer
双写缓冲: Innodb和操作系统的页大小不一致 前者16K后者4K ,会存在分批写的情况,如果写的途中出现崩溃的情 况, 这个时候页出现损坏,这个时候redo log的崩溃恢复没法生效,发生数据丢失。innodb 为我们提供双写 的 机制,先拷贝一份数据的副本,如果崩溃,就将副本恢复,再使用redo log。
独占表空间: 可以为每个表设置为独占表空间
临时表空间:
通用表空间:
redo log:记录数据到磁盘,用于崩溃恢复,保证事务的持久性
undo log:撤销回滚日志 记录事务发生之前的状态,如果发生异常,可以使用undo log回滚。
bin log ,server层的日志。主要是用来主从复制(原理就是读取主库的bin log,执行一遍sql),数据恢复。记录所有的sql语句,有点aof的味道,可以将操作重复实现数据恢复。和redo log不一样,他的内容可以追加,没有大小限制
更新的流程:
1、事务开始,从内存或磁盘读取这条数据,返回给server执行器
2、记录数据到 undo log
3、调用存储引擎api,将结果修改内存(buffer pool)
4、记录数据到redo log(二阶段提交 prepare commit),将这一行数据记录为prepare
5、写入bin log
6、commit 提交事务
7、将redo log事务状态设置为commit
8、等待工作线程刷脏
上面是mysql的一些底层存储情况,下面介绍一下索引
索引是什么?
是数据库中一种排序的数据结构,用来协助于快速查询和更新数据表。
索引记录的是索引字段信息+对应的磁盘地址,以便于快速查找
索引类型:
普通索引nomol 、 唯一索引unique、全文索引 fulltext
普通索引,没有任何限制
唯一索引,唯一性约束,主键是特殊的唯一索引
全文索引,针对比较大的数据,查询部分内容,使用like性能低,我们可以再文本类型上建全文索引
mysql索引存储模型的演进推倒:
1、我们想用什么数据结构,来存储,实现快速定位?
数组或者链表,但是存在修改的情况,使用链表 但存在问题,链表从上往下查询,数据量大时,效率低O(n)
2、链表效率低,2分增加效率 使用二叉查找数
提高了效率,但是二叉查找树极端情况会变成链表,依旧时O(n)
3、平衡二叉查找数 可以在数据分布不均匀的时候,利用左旋和右旋,实现平衡
平衡二叉树解决了分布问题,但是查询效率受树的度所影响,会出现瘦长的树,效率不高
4、B Tree 可以使用多路的特性(路数比关键字数多1),将二叉演进成多叉,将瘦长的树,转换为矮胖的那种,符合条件
还能不能再进一步了,优化一波
5、B+Tree (加强版)
特点:路数和关键字数相等
根节点和枝节点不存数据,只有叶子节点存数据
叶子节点维护了一个指针,指向相邻的叶子节点,形成一个有序列表
根据左闭右开的区间来检索数据
优势: 1、存储的数据量大,一个三层的B+Tree就可以存储千万级数据,查询效率高
数据量大的原因:
路数和关键字相等
根节点和枝节点不存数据,所消耗的空间就更少,所存储的子节点的路数就更多
2、所有的数据都存在叶子节点,查询效率稳定
3、叶子节点维护了一个类似于链表的指针,范围查询时快,不需要每次都从上往下查一遍
4、扫库扫表能力强,所有数据都在叶子节点上
了解:
为什么不用红黑树?
红黑树的特点:节点分为红色和黑色
根节点必须是黑色
叶子节点都是黑色的null节点
红色节点的两个子节点都是黑色(不允许相邻两个红节点)
从任意节点,到每个叶子节点路径上包含相同的黑色节点
原因:红黑树是二叉,只有两路 不够平衡
MYISAM和INNODB的索引存储形式:
show VARIABLES LIKE 'datadir';查看数据存储路径
MYISAM:
生成的文件:
user_myisam.frm
user_myisam.MYD
user_myisam.MYI
.frm存储的是表结构定义信息等数据。
.MYD D代表data 存储的数据文件,存放的是所有的数据信息
.MYI I代表index 存储的是索引信息
也就是说,在MYISAM内部,其实B+Tree中维护的叶子节点,也全部都是数据文件的地址信息,根据MYI中的index的地址,然后查询.MYD。主键索引和辅助索引都是这种形式
INNODB内部结构:
user_innodb.frm 存储表结构定义信息
user_innodb.ibd 存储索引文件和数据(B+Tree内部)
主键索引的所有数据,都存在叶子节点上
辅助索引,通过主键索引来实现查找(回表)
辅助索引存储的是主键的值,然后通过这个值去主键索引中查找
为什么存主键的值,不存地址?因为会存在分裂合并的情况,地址会变,不利于维护
如果没有主键怎么办?
1、定义了主键,会使用主键
2、没有主键,会选择第一个不包含null的一个唯一索引
3、没有唯一索引,会使用内置的ROWID,并随着记录写入,递增
索引使用的原则:
肯定不是越多越好,占空间,插入需要写入更多的,耗性能
列的离散度 count(distinct(column_name)) : count(*) 离散度越高,数据区分度越大,重复值越少,适合
联合索引的最左匹配:(name,phone)
联合索引是复合数据结构,按照从左到右的顺序来创建索引树
查询时是先根据name去匹配,匹配到了,再根据phone匹配。匹配不到,就不知道往哪去查了
所以建联合索引的时候,一定要把最常用的列放在最左边。
思考下哪个用不到索引:
SELECT * FROM user_innodb WHERE name= '权亮' AND phone='15204661800';
SELECT * FROM user_innodb WHERE name= '权亮';
SELECT * FROM user_innodb WHERE phone='15204661800';
创建的话,按照最左匹配原则,(a,b,c)其实本质已经有了(a)(a,b) (a,b,c)无需重复创建
覆盖索引:
上面也介绍过,辅助索引有回表的情况,多了一次io,但是如果只查询索引包含的数据,就不用回表,也提醒我们,不要select *,只查询自己需要的数据
索引的创建和使用原则:
1、在where和order join使用的字段上创建索引
2、索引个数不要太多,按需(浪费空间,更新变慢)
3、区分度低的数据,不要建索引(大量数据一致,扫描行数过高)
4、频繁更新的值,不要作为主键或者索引(页分裂)
5、组合索引 区分度高的放在左边,最左原则
6、适当使用复合索引
什么时候用不到索引:
1、索引列上使用函数、计算 SELECT*FROM`t2`whereid+1=4;
2、字符串不加引号,出现隐式转换
3、like条件中前面使用%
索引介绍完了,讲一下事物
事物的定义:
数据库的逻辑单元(最小的工作单位),由一个有限的数据库操作序列构成(一个或多个DML)。
事物的特性ACID:
1、原子性Atomicity:事物是数据库的最小的逻辑单元,内部所有操作,要么全部成功,要么全部失败。(使用undo log来实现)
2、一致性consistent: 主要是两个方面,一个是数据库层面(完整性约束保持一致,不会被破坏) 一个是业务层面,业务约束满足(举例:A转账B A1000 转账成功 B 收到500 也成功,满足原子性都成功了,但是不满足一致性,账目不对)
3、隔离性 Isolation: 数据库有事物存在,就会同时有许多事物共同运行,隔离性主要就是为了让事物之间操作透明,互补干扰
4、持久性 Durable :持久性的意思就是,一个事物操作,只要事物提交了,结果就是持久性的,不会因为服务器宕机重启丢失,实现方式其实主要就是redo log + dubbo write 来实现。
***:原子性 隔离性 持久性 是手段,目的都是为了实现一致性
什么时候出现事物:
1、自动提交,默认打开 show variables like 'autocommit';
2、手动: begin; / start transaction; commit; rollback;
事物并发会带来什么问题?
1、脏读 (读到另外一个事物里面未提交的数据)
2、不可重复读(读到另外一个事物已提交的事物-修改,数据前后不一致情况)
3、幻读 (读到另外一个事物,新增的数据)
这三个统一是读一致性问题,必须由数据库厂家的事物隔离界别