MySQL学习笔记-从基础到进阶

MySQL

课程连接

数据库:存储数据的仓库,数据是有组织的进行存储(DataBase, DB)

数据库管理系统:操纵和管理数据库的大型软件(DataBase Management System, DBMS)

SQL : 操作关系型数据库的编程语言,定义了一套操作关系型数据库的统一标准(Structured Query Language, SQL)

在这里插入图片描述

基础

  • 关系型数据库(RDBMS)

    • 概念:建立在关系模型基础上,有多张相互连接的二维表组成的数据库
    • 使用表存储数据,格式统一,便于维护
    • 使用SQL语言操作,标准统一,使用方便
  • MySQL启动

  net start mysql80
  net stop mysql80
* MySQL客户端连接
  mysql [-h 127.0.0.1] [-p 3306] -u root -p
  • MySQL数据模型
    • 数据库管理系统 --> 数据库 --> 二维表

SQL

SQL通用语法
  • SQL语句可以单行或多行书写,以分号结尾
  • SQL语句可以使用空格/缩进来增强语句的可读性
  • MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
  • 注释
    • 单行注释:–或#
    • 多行注释:/* */
SQL分类
  • DDL (Data Definition Language) 数据定义语言,用来定义数据库对象(数据库、表、字段等)
  • DML(Data Manipulation Language) 数据操作语言,用来对数据库表中的数据进行增删改查
  • DQL(Data Query Language) 数据查询语言,用来查询数据库中标的记录
  • DCL(Data Control Language) 数据控制语言,用来创建数据库用户、控制数据库的访问权限
DDL数据操作
  • 查询
  #查询所有数据库
  SHOW DATABASES;
  #查询当前数据库
  SELECT DATABASE();
  • 创建
  CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集(UTF8MB4)] [COLLATE 排序规则];
  • 删除
  DROP DATABASE [IF EXISTS] 数据库名;
  • 使用
  USE 数据库名;
  • 表操作-查询
  #查询当前数据库所有表
  show tables;
  #查询表结构
  desc 表名;
  #查询指定表的建表语句
  show create table 表名;
  • 表操作-创建
  create table 表名(
         字段1  字段1类型  [comment 字段1注释],
         字段2  字段2类型  [comment 字段2注释],
         字段3  字段3类型  [comment 字段3注释],
         ......
         字段n  字段n类型  [comment 字段n注释]
  )[comment 表注释];
  #注意:[..]为可选参数,最后一个字段结束没有逗号
  • 表操作-修改
  #添加字段
  alter table 表名 add 字段名 类型(长度)[comment 注释] [约束];
  #修改字段数据类型 
  alter table 表名 modify 字段名 新数据类型(长度);
  #修改字段名和字段类型
  alter table 表名 change 旧字段名 新字段名 类型(长度) [comment 注释] [约束];
  #删除字段
  alter table 表名 drop 字段名;
  #修改表名
  alter table 表名 rename to 新表名;
  #删除表
  drop table [if exists] 表名;
  #删除指定表,并重新创建该表
  truncate table 表名;
数据类型
  • 数据类型-数值类型

在这里插入图片描述

  • 数值类型-字符类型

在这里插入图片描述

  • 数值类型-日期类型

在这里插入图片描述

DML数据操作
  • INSERT添加数据
  #给指定字段添加数据
  INSERT INTO 表名(字段名1,字段名2...) VALUES(1,值2,...);
  #给全部字段添加数据
  INSERT INTO 表名 VALUES(1,值2,...);
  #批量添加数据
  INSERT INTO 表名(字段名1,字段名2...) VALUES(1,值2,..),(1,值2,..),(1,值2,..);
  INSERT INTO 表名 VALUES(1,值2,...),(1,值2,...),(1,值2,...);
  #注意:插入数据时,指定字段顺序需要与值的顺序是一一对应的
  #字符串和日期类型数据应该包含在引号中;
  #插入数据的大小,应该在字段的规定范围内
  • UPDATE修改数据
  #修改数据
  UPDATE 表名 SET 字段名1 =1, 字段名2 =2,...[WHERE 条件];
  #修改语句条件可以有或没有,如果没有默认修改整张表的所有数据
  #删除数据
  DELETE FROM 表名 [WHERE 条件];
  #DELETE语句的条件可以有,也可以没有,如果没有条件,则删除整张表的数据
  #DELETE语句不能删除某一字段的值(可以使用UPDATE)
DQL数据操作
  • 基本查询
  #查询多个字段
  SELECT 字段1, 字段2... FROM 表名;
  SELECT * FROM 表名;
  #设置别名 AS可省略
  SELECT 字段1[AS 别名1], 字段2[AS 别名2]...FROM 表名;
  #去除重复记录
  SELECT DISTINCT 字段列表 FROM 表名;
  • 条件查询
  SELECT 字段列表 FROM 表名 WHERE 条件列表;
  #条件
  BETWEEN [MAX] AND [MIN]; --在某一范围内,相当于 MIN <= AND <=MAX
  VALUE1 IN(VALUE2, VALUE3,);  --相当于 VALUE1 = VALUE2 OR VALUE1 = VALUE3
  IS NULLIS NOT NULL; --查询为NULL和不为NULL
  LIKE '_ _'; --查询两个字符的字段
  LIKE '%X'; --查询最后为X的字段

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 聚合函数
  #将一列数据作为一个整体,进行纵向计算的函数-聚合函数
  count --统计数量
  max --最大值
  min --最小值
  avg --平均值
  sum --求和
  # NULL值不参与函数运算
  #语法
  SELECT 聚合函数(字段列表) FROM 表名;
  • 分组查询
  SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件];
  #WHERE 与 HAVING区别
  #执行时机不同:WHERE是分组前进行过滤,不满足条件,不参与分组。HAVING是分组之后对结果进行过滤。
  #判断条件不同:WHERE不能对聚合函数进行判断,HAVING 可以。
  #执行顺序:WHERE > 聚合函数 > HAVING
  #分组后一般查询分组字段和聚合函数,查询其他字段没有意义
  • 排序查询
  SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;
  #排序方式
  ASC 升序 默认值
  DESC 降序
  #注意:如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序
  • 分页查询
  SELECT 字段列表 FROM 表名 LIMIT 起始索引,查询记录数;
  #注意:起始索引从0开始,起始索引 = (查询页码-1)*每页显示记录数
  #分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是LIMIT
  #如果查询的是第一页数据,起始索引可以省略,直接简写为 LIMIT 10
  • 执行顺序
  #编写顺序
  SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY -> LIMIT 
  #执行顺序
  FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT
DCL数据控制
  • 用户管理
  #查询用户
  USE mysql;
  SELECT * FROM user;
  #创建用户 
  CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
  #修改用户密码
  ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
  #删除用户
  DROP USER '用户名'@'主机名';
  #注意:主机名可以使用%通配
  #这类操作开发人员操作较少,主要是DBA(Database Adminstrator 数据管理员)使用。
  • 权限控制
  #查询权限
  SHOW GRANTS FOR '用户名'@'主机名';
  #授予权限
  GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
  #撤销权限
  REVOKE 权限列表 ON 数据库名。表名 FROM '用户名'@'主机名';

在这里插入图片描述

函数
  • 字符串函数
  SELECT 函数(参数);

在这里插入图片描述

  • 数值函数

在这里插入图片描述

  • 日期函数

在这里插入图片描述

  • 流程函数

在这里插入图片描述

约束
  • 概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据

  • 目的:保证数据库中数据的正确、有效性和完整性

  • 分类:

在这里插入图片描述

  AUTO_INCREMENT 使约束字段递增
  • 注意:约束是作用于表中字段上,可以在创建表/修改表时添加约束

  • 外键约束:外键用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性

  #添加外键
  CREATE TABLE 表名(
         字段名 数据类型,
         ...
         [CONSTRAINT] [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名)       
  );ALTER TABLE 表名 ADD CONSTRAINT [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名);
  #删除外键
  ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
  • 外键约束删除/更新行为
  ALTER TABLE 表名 ADD CONSTRAINT [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名) ON UPDATE 行为 ON DELETE 行为;
  # NO ACTION 、RESTRICT 默认行为

在这里插入图片描述

多表查询
  • 多表关系
  #一对多(多对一) 如员工与职位的关系
  实现:在多的一方建立外键,指向一的一方的主键
  #多对多 如学生与课程的关系
  实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
  #一对一  多用于单表拆分
  实现:在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)
  • 多表查询
  #连接查询 注意消除笛卡尔积的条件
  内连接:相当于查询A、B交集部分数据
  ##隐式内连接
  SELECT DISTINCT 字段列表 FROM1,表2 WHERE 连接条件...;
  DISTINCT对查询结果去重
  ##显式内连接
  SELECT 字段列表 FROM1 [INNER] JOIN2 ON 连接条件...;
  外连接:
      左外连接:查询左表所有数据,以及两张表交集部分数据
  SELECT 字段列表 FROM1 LEFT [INNER] JOIN2 ON 连接条件... [WHERE 条件];
      右外连接:查询右表所有数据,以及两张表交集部分数据
  SELECT 字段列表 FROM1 RIGHT [INNER] JOIN2 ON 连接条件... [WHERE 条件];
  自连接:当前表与自身的连接查询,自连接必须使用表别名
  
  #联合查询
  对于UNION查询,是把多次查询的结果合并起来,形成一个新的查询结果集
  SELECT 字段列表 FROM 表A ...
  UNION[ALL]
  SELECT 字段列表 FROM 表B...;
  注意:对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致
       UNION ALL会将全部的数据直接合并在一起,UNION会对合并之后的数据去重
  #子查询
  SQL语句中嵌套SELECT语句,称为嵌套查询,又称为子查询
  SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
  子查询外部的语句可以是INSERT/ UPDATE / SELECT / DELETE 的任何一个
  根据子查询结果不同,分为:
      标量子查询(子查询结果为单个值)
      列子查询(子查询结果为一列)
      行子查询(子查询结果为一行)
      表子查询(子查询结果为多行多列)
  根据子查询位置,分为:WHERE之后、FROM之后、SELECT之后。
事务
  • 事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或撤销操作请求,这些操作要么同时成功,要么同时失败

  • 默认MySQL的事务是自动提交的

  • 事务操作

  #查看/设置事务提交方式
  SELECT @@autoaommit;
  SET @@autocommit = 0; -- 0 手动提交 1 自动提交
  #提交事务
  COMMIT;
  #回滚事务
  ROLLBACK;
  
  #方式二 不用设置系统参数
  #开启事务
  START TRANSACTIONBEGIN
  #提交事务
  COMMIT;
  #回滚事务
  ROLLBACK;
  • 事务四大特性
  原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败
  一致性(Consistency):事务完成时,必须使所有的数据保持一致状态
  隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
  持久性(Durability):事务一旦提交或回滚,他对数据库中的数据的改变是永久的
  • 并发事务问题
  脏读:一个事务读取到另外一个事务还没有提交的数据
  不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,成之为不可重复读
  幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了’幻影‘
  • 并发事务隔离级别

在这里插入图片描述

  上表从上到下隔离级别越来越高,性能越来越差,安全性越来越高
  --查看事务隔离级别
  SELECT @@TRANSACTION_ISOLATION;
  --设置事务隔离级别 SESSION[当前窗口有效] GLOBAL[所有窗口有效]
  SET[SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {隔离级别}

进阶

存储引擎

  • MySQL体系结构

在这里插入图片描述

  --连接层:最上层是一些客户端和连接服务,主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限
  --服务层:第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等
  --引擎层:存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎
  --存储层:主要将数据存储在文件系统之上,并完善与存储引擎的交互
  • 存储引擎
  #指定存储引擎 默认INNODB
  CREATE TABLE 表名(
        
  )ENGINE = 存储引擎 [COMMENT 表注释];
  #查询数据库支持的引擎
  SHOW ENGINE;
  • 存储引擎特点
  #innoDB
  innoDB是一种兼顾高可靠性和高性能的通用存储引擎,在MySQL5.5之后,是默认存储引擎
  #特点
  DML操作遵循ACID模型,支持事务
  行级锁,提高并发访问性能
  支持外键FOREIGN KEY约束,保证数据的完整性和正确性
  #文件
  xxx.idb: xxx表示表名,innoDB引擎的每张表都会对应这样一个表空间文件,存储该表的表结构(frm sdi)、数据和索引。
  参数:innodb_file_per_table -- 是否开启一张表对应一个表空间文件

在这里插入图片描述

  #MySAM
  早期的默认存储引擎
  #特点
  不支持事务,不支持外键
  支持表锁,不支持行锁
  访问速度快
  #文件
  xxx.sdi --存储表结构信息
  xxx.MYD --存储数据
  xxx.MYI --存储索引
  
  #Memory
  其数据表存储在内存中,由于受到硬件问题、或断点问题的影响,只能将这些表作为临时表或缓存使用
  #特点
  内存存放
  hash索引
  #文件
  xxx.sdi

在这里插入图片描述

  • 存储引擎选择

在这里插入图片描述

索引(重点)

  • 索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

  • 优缺点

在这里插入图片描述

  • 索引结构

MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的结构,主要包含一下几种:

在这里插入图片描述在这里插入图片描述

  • B-Tree(多路平衡查找树)

二叉树缺点:顺序插入时,会形成一个链表,查询性能大大降低。大数据量情况下,层级较深,检索速度慢

红黑树:大数据量情况下,层级较深,检索速度慢

B-Tree:以一颗最大度数(max-degree)为5阶的B-Tree为例(每个节点最多存储4个key,5个指针),树的度数指的是一个节点的子节点个数

在这里插入图片描述

  • B+Tree

在这里插入图片描述

​ 与B-Tree区别:所有的数据都会出现在叶子节点;叶子节点形成一个单向列表。

  • MySQL索引数据结构对经典B+Tree进行了优化,在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能
    在这里插入图片描述

  • Hash索引

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash 表中。如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了hash冲突(hash碰撞),可以通过链表解决。

特点:hash索引只能用于对等比较(=、in),不支持范围查询(between、>  、< ...)
     无法利用索引完成排序操作;
     查询效率高,通常只需要一次检索就可以了,效率通常高于B+Tree索引

​ 在MySQL中,支持hash索引的值Memory引擎,而innoDB中具有自适应hash功能,hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的。

  • 为什么InnoDB存储引擎选择使用B+Tree索引结构?

    1、相对于二叉树,层级更少,搜索效率高

    2、对于B-Tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页存储的键值减小,指针跟着减小,同样保存大量的数据,只能增加树的高度,导致性能降低

    3、相对于Hash索引,B+Tree支持范围匹配和排序操作

  • 索引分类

在这里插入图片描述

在InnoDB引擎中,根据索引的存储形式,又可以分为一下两种:

在这里插入图片描述

  • 聚集索引选取规则

    1、如果存在主键,主键索引就是聚集索引

    2、如果不存在主键,将使用第一个唯一索引作为主键索引

    3、如果表没有之间,或没有合适的唯一索引,则引擎会自动生成一个rowid作为隐藏的聚集索引

  回表查询:先走二级索引找到对应的主键值,再根据主键值走聚集索引找到对应的行数据
  • 索引语法
  --创建索引
  CREATE [UNIQUE | FULLTEXT] INDEX index_name ON table_name (index_col_name,...);
  --查看索引
  SHOW INDEX FROM table_name;
  --删除索引
  DROP INDEX index_name ON table_name;
  • SQL性能分析
  --执行频次
  MySQL客户端连接成功后,通过下面指令可以提供服务器状态信息。查看当前数据库的INSERT\UPDATE\
  DELETE\SELECT的访问频次: 
  SHOW [SESSION|GLOBAL] STATUS LIKE 'Com_____';  --Com下划线,几个表示几个字符
  --慢查询日志
  慢查询日志记录了所有执行时间超过指定参数(long_query_time 默认10秒)的所有SQL语句的日志。MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/mysql/mysql.conf.d/mysqld.cnf)中配置如下信息,可以使用 vi/vim修改:
  #开启MySQL慢查询日志开关
  slow_query_log = 1;
  #设置慢查询日志的时间,超过指定时间,就视为慢查询,记录在慢查询日志
  long_query_time = 2;
  #慢查询日志文件位置( /var/log/mysql/mysql-slow.log)
  slow_query_log_file    = /var/log/mysql/mysql-slow.log
  --查看慢查询日志是否开启
  SHOW VARIABLES LIKE 'slow_query_log';
  --查看慢查询日志实时内容
  tail -f mysql-slow.log
  --其他ubuntu常用指令
  重启MySQL systemctl restart mysql
  关闭MySQL systemctl stop mysql
  --profile详情
  show profiles能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。通过have_profiling参数,能够看到当前MySQL是否支持profile操作:
  SELECT @@have_profiling;
  --默认profiling是关闭的,可以通过set语句在session(当前会话)/global(全局)级别开启profiling:
  SELECT @@profiling; --查看是否开启
  SET profiling = 1;
  --查看每一条SQL指令执行耗时情况
  SHOW profiles;
  --查看指定query_id的SQL语句各个阶段的耗时情况
  show profile for query query_id;
  --查看指定query_id的SQL语句CPU的使用情况
  show profile cpu for query query_id;
  --explain执行计划
  EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。语法:
  #直接在SELECT语句之前加上关键字EXPLAIN/DESC
  EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;

在这里插入图片描述

  --各字段含义
  id: SELECT查询的序列号,表示查询中执行SELECT子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越优先执行);
  select_type: 表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层查询)、UNIONUNION中第二个或者后面的查询语句)、SUBQUERY
  (SELECT/WHERE之后包含了子查询)等;
  type: 表示连接类型,性能由好到差的连接类型为NULL 、system 、const 、eq_ref、ref、range、indexall;
  possible_key: 显示可能应用在这张表上的索引,一个或多个;
  key: 实际使用的索引,如果为NULL,则没有使用索引;
  key_len: 表示索引中引用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好;
  rows: MySQL认为必须要执行查询的行数,在innoDB引擎的表中,是一个估计值,可能并不总是准确的;
  filtered: 表示返回结果的行数占需读取行数的百分比,filtered的值越大越好;
  Extra: 额外的信息。
  • 索引使用

    • 最左前缀法则:如果索引了多列(联合索引),要遵循最左前缀法则。其指的是查询从索引的最左列开始,并且不跳过索引中的列,与索引时字段的位置没有关系。如果跳过某一列,索引将部分失效(后面的字段索引失效),这个与创建索引时的顺序有关。
    • 范围查询:联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效。尽量使用(>=,<=)。
    • 索引列运算:不要在索引列上进行运算操作,索引将失效。
    • 字符串不加引号:字符串类型字段使用索引时,如果不加引号,索引将失效。
    • 模糊查询:如果仅仅是尾部模糊匹配(like ‘xx%’),索引不会失效。如果头部模糊匹配(like ‘%xx’),索引失效。
    • or 连接条件:用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都会失效。即使左侧有索引,右侧有联合索引,右侧相当于没有索引,依然or两侧索引失效。
    • 数据分布影响:如果MySQL评估使用索引比全表扫描更慢,则不使用索引。
  • SQL提示

  --SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的
  use index: 建议使用某个索引,最终取决于MySQL
  explain select 字段列表 from 表名 use index(索引名) where 条件;
  ignore index: 不要使用某个索引
  explain select 字段列表 from 表名 ignore index(索引名) where 条件;
  force index: 必须使用某个索引
  explain select 字段列表 from 表名 force index(索引名) where 条件;
  • 覆盖索引
  覆盖索引:在查询使用了索引,并且需要返回的字段或列,在该索引中都能找到。尽量使用覆盖索引,减少select *
  
  --extra 信息
  using index condition :查找使用了索引,但需要回表查询数据
  using where;using index: 查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询
  • 前缀索引
  当字段类型为字符串(varchar,text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO,影响查询效率。此时可以只将字符串的一部分前缀建立索引,这样大大节约索引空间,提升效率。
  --语法:
  create index idx_name on table_name(column(n));
  --前缀长度
  可以根据索引的选择性来决定,而选择性是指不重复的索引值和数据表的记录总数的壁纸,索引选择性越高,查询效率就越高,唯一索引的选择性为1select count(distinct 字段) /count(*) from 表名;
  select count(distinct substring(字段,start,length )) /count(*) from 表名;
  • 单列索引与联合索引
  单列索引:一个索引只包含单个列
  联合索引:一个索引包含多列
  如果存在多个查询条件,建议建立联合索引,使用时注意最左前缀法则
  • 索引设计原则

在这里插入图片描述

SQL优化

  • insert优化
  --批量插入
  insert into table_name values(),(),().....;
  --手动提交事务
  start transaction;
  insert into ...;
  ...
  insert into ...;
  commit;
  --主键顺序插入
  主键数据顺序插入要比乱序效率高
  --大批量插入数据
  如果一次性插入大量数据,使用insert性能较低,此时可以使用MySQL数据库提供的load指令进行插入:
  #客户端连接服务器时,加上参数 --local-infile
  mysql --local-infile -u root -p
  #设置全局参数 local-infile为1,开启从本地加载文件导入数据的开关
  select @@local-infile; -- 查看状态
  set local-infile = 1; --开启
  #执行load指令将数据加载到表结构中
  load data local infile '文件位置' into table '表名' fields terminated by '数据分隔符' lines terminated by '换行符 \n';
  • 主键优化
  --数据组织方式InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表(index organized table,IOT)
  --页分裂
  页可以为空,也可以存储一半,也可以存储100%。每个页包含2-N行数据(如果一行数据过大,会行溢出),根据主键排列。至少包含两行数据的原因是,如果只存放一列,而数据又是顺序组织存放,就形成了链表
  如果主键数据乱序存放,可能发生页分裂现象
  --页合并
  当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记为删除并且它的空间变得允许被其他记录声明使用。当页中删除的记录达到MERGE_THRESHOLD(默认为页的50%)InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
  MERGE_THRESHOLD: 合并页的阈值,可以在创建表或创建索引时指定。
  --主键设计原则
  满足业务需求的情况下,尽量降低主键的长度;
  插入数据时,尽量选择顺序插入,选择使用auto_increment自增主键;
  尽量不要使用uuid做主键或者其他自然主键,如身份证号;
  业务操作时,避免对主键修改。
  • order by
  --order by 排序
  Using filesort :通过表的索引或全表扫描,读取满足条件的数据行,然后在缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫filesort.
  Using index: 通过有序索引顺序扫描直接返回有序数据,这种情况为using index,不需要额外排序,效率高
  --优化设置
  根据排序字段建立合适的索引,多字段排序时,可建立联合索引,遵循最左前缀法则;
  尽量使用覆盖索引;
  多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(asc / desc);
  如果不可避免出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size(默认256k)
  • group by优化
  在分组操作时,可以通过索引来提高效率;
  分组操作时,索引的使用也要满足最左前缀法则。
  • limit优化
  一般分页查询时,通过创建 覆盖索引 能够比较好提高性能,可以通过覆盖索引加子查询形式进行优化
  • count优化
  myisam引擎把一个表的总数存在了磁盘上,因此执行count(*)的时候会直接返回这个数,效率较高
  innoDB引擎执行count(*)时,需要把数据一行一行地从引擎里面读出来,然后累积计数
  优化思路:自己计数

在这里插入图片描述

  • update优化
  InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则会从行锁升级为表锁
  在使用update修改数据时,尽量使用索引作为条件,防止在事务并发操作时,行锁升级为表锁,影响运行效率

视图

  • 定义:视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。

  • 语法

  --创建
  CREATE [OR REPLACE] VIEW 视图名称[(列名列表)] AS SELECT语句 [WITH [CASCADED | LOCAL] CHECK OPTION];
  --查询
  查看创建视图语句:SHOW CREATE VIEW 视图名称;
  查看视图数据: SELECT * FROM 视图名称 ..;
  --修改
  1) CREATE [OR REPLACE] VIEW 视图名称[(列名列表)] AS SELECT语句 [WITH [CASCADED | LOCAL] CHECK OPTION];
  2) ALTER VIEW 视图名称[(列名列表)] AS SELECT语句 [WITH [CASCADED | LOCAL] CHECK OPTION];
  --删除
  DROP VIEW [IF EXISTS] 视图名称,...;
  • 视图检查选项
  --当使用WITH CHECK OPTION子句创建视图时,MySQL会通过视图检查正在更改的每个行,例如插入、更新、删除,以使其符合视图的定义。MySQL允许基于另一个视图创建视图,他还会检查依赖视图中的规则以保持一致性。为例确定检查范围,MySQL提供了两个选项:CASCADED和LOCAL,默认值为CASCADED(级联)。
  --CASCADED:
  --基于视图(未加检查条件)创建视图时没有加检查选项,在增删改时不会检查自身创建条件,但是会判断视图的条件,如果满足两个视图的条件则结果出现在视图中,反之不然。如果创建的视图加上了检查选项,不仅会检查自身条件,还会检查基于的视图条件,有一个视图不满足条件都会报错。
  --LOCAL:
  --基于视图(未加检查条件)创建视图时没有加检查选项,在增删改时不会检查自身创建条件,但是会判断视图的条件,如果满足两个视图的条件则结果出现在视图中,反之不然。如果创建的视图加上了检查选项,只会检查自身条件,不会检查基于的视图条件,不满足创建视图的条件才会报错。
  • 视图的更新
  --要使视图可更新,视图中的行与基表中的行之间存在一对一关系。如果视图包含一下任何选项,则该视图不可更新:
  1、聚合函数或窗口函数(SUM() MIN() MAX() COUNT()2DISTINCT
  3GROUP BY
  4HAVING
  5UNION 或者 UNION ALL
  --视图作用
  --简单
  视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作指定全部的条件。
  --安全
  数据库可以授权,但不能授权到数据库特定的行或特定的列上。通过视图用户只能查询和修改他们所能见到的数据。
  --数据独立
  视图可以帮助用户屏蔽真实表结构变化带来的影响。

存储过程

  • 定义

    存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有利的。

    存储过程思想就是数据库SQL语言层面的代码封装与重用

  • 特点

    1、封装、复用

    2、可以接受参数,也可以返回数据

    3、减少网络交互,提升效率

  • 语法

  -- 创建
  CREATE PROCEDURE 存储过程名([参数列表])
  BEGIN
      -- SQL语句
  END;
  -- 调用
  CALL 名称([参数]);
  -- 查看
  -- 查询指定数据库的存储过程及状态信息
  SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '数据库名'; 
  -- 查询某个存储过程的定义
  SHOW CREATE PROCEDURE 存储过程名称;
  -- 删除
  DROP PROCEDURE [IF EXISTS] 存储过程名称;
  
  -- 注意
  在命令行中,执行存储过程的SQL时,需要通过关键字 delimiter 指定SQL语句的结束符
  • 变量
  -- 系统变量
  系统变量时MySQL服务器提供,不是用户定义的,属于服务器层面。分为全局变量(GLOBAL)、会话变量(SESSION)
  -- 查看系统变量
  SHOW [SESSION | GLOBAL] VARIABLES; -- 查看所有系统变量
  SHOW [SESSION | GLOBAL] VARIABLES LIKE '...'; -- 可以通过LIKE模糊匹配方式查找变量
  SHOW @@[SESSION | GLOBAL] 系统变量名; -- 查看指定变量的值
  -- 设置系统变量
  SET [SESSION | GLOBAL ] 系统变量名 =;
  SHOW @@[SESSION | GLOBAL] 系统变量名 =;
  -- 注意
  如果没有指定 SESSION/ GLOBAL,默认为 SESSION;
  MySQL服务器重新启动之后,所设置的全局参数会失效,如果想不失效,配置 my.cnf
  
  -- 用户定义变量
  用户定义变量是根据用户需要自己定义的变量,用户变量不用提前声明,在用的时候直接用 "@变量名"使用。其作用域为当前连接会话
  -- 赋值
  SET @var_name = value, [@var_name = value],...;
  SET @var_name := value, [@var_name = value],...;
  SELECT @var_name := value, [@var_name = value],...;
  SELECT 字段名/聚合函数 INTO @var_name FROM 表名;
  -- 使用
  SELECT @var_name;
  -- 注意
  用户自定义变量无需进行声明或初始化,只不过获取到的值为NULL
  
  -- 局部变量
  局部变量是根据需要定义在局部生效的变量,访问之前,需要 DECLARE 声明。可用作存储过程内的局部变量和输入参数,局部变量的范围是在其内部声明的 BEGIN ... END-- 声明
  DECLARE 变量名 变量类型 [DEFAULT value];
  -- 变量类型就是数据库的字段类型
  -- 赋值
  SET 变量名 =;
  SET 变量名 :=;
  SELECT 字段名 INTO 变量名 FROM 表名 ...;
  • 参数
  -- 参数类型
  IN :该类参数作为输入,也就是需要调用时传入值 ,默认
  OUT :该类参数作为输出,也就是需要调用时传出值,需要定义用户变量接收
  INOUT :既可以作为输入参数,又可以作为输出参数
  -- 用法
  CREATE PROCEDURE 存储过程名([IN / OUT / INOUT 参数名 参数类型])
  BEGIN
     SQL
  END;
  • 流程控制
  -- if
  IF 条件1 THEN
   ...
  ELSEIF 条件2 THEN
   ...
  ELSE
   ...
  END IF;
  -- case
  -- 1
  CASE case_value
       WHEN when_value1 THEN 语句
       [WHEN when_value1 THEN 语句]
       ...
       [ELSE 语句]
  END CASE;  
  -- 2
  CASE
       WHEN 条件表达式1 THEN 语句
       [WHEN 条件表达式2 THEN 语句]
       ...
       [ELSE 语句]
  END CASE;     
  -- while
  WHILE 条件 DO
     SQL逻辑
  END WHILE;   
  -- repeat 循环
  #先执行一次SQL语句,然后判定条件是否满足,如果满足则退出循环,不满足继续下一次循环
  REPEAT 
      SQL逻辑
      UNTIL 条件
  END REPEAT; 
  -- loop
  #LOOP实现简单循环,如果不在SQL逻辑中增加退出循环的条件,可以用其来实现简单的死循环。LOOP可以配合两条语句使用:
  LEAVE -- 配合循环使用,退出循环
  ITERATE -- 必须用在循环中,作用是跳过当前循环剩下的语句,直接进入下一次循环
  [begin_label:] LOOP
         SQL逻辑
  END LOOP[end_label];
  LEAVE label; -- 退出指定标记的循环体
  ITERATE label; -- 直接进入下次循环
  • 游标
  -- 定义
  游标(CURSOR)是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环处理。游标的使用包括游标的声明、OPENFETCH、和CLOSE
  -- 声明游标
  DECLARE 游标名称 CURSOR FOR 查询语句;
  -- 打开游标
  OPEN 游标名称;
  -- 获取游标记录; 定义变量,创建表格,循环获取游标数据,并给表格插入数据
  FETCH 游标名称 INTO 变量 [, 变量]..;
  -- 关闭游标
  CLOSE 游标名称;
  -- 注意
  变量的声明要在游标声明之前
  • 条件处理程序
  -- 条件处理程序(handler)可以用来定义在流程控制结构执行过程中遇到问题时行营的处理步骤。
  DECLARE handler_action HANDLER FOR condition_value [,condition_value]... 逻辑语句;
  -- handler_action
  CONTINUE :继续执行当前程序
  EXIT :终止执行当前程序
  -- condition_value
  SQLSTATE sqlstate_value :状态码 如‘02000’
  SQLWARNING :所有以01开头的 SQLSTATE代码的简写
  NOT FOUND :所有以02开头的 SQLSTATE代码的简写
  SQLEXCEPTION :所有没有被 SQLWARNING和 NOT FOUND捕获的 SQLSTATE代码的简写
  • 存储函数
  -- 存储函数是有返回值的存储过程,存储函数的参数只能时IN类型。
  CREATE FUNCTION 函数名([参数列表])
  RETURNS type(参数列表的数据类型) [characteristic ...]
  BEGIN
      --SQL
      RETURN ...;
  END;
  -- characteristic
  DETERMINISTIC :相同的输入参数总是产生相同的结果
  NO SQL :不包含SQL语句
  READS SQL DATA :包含读取数据的语句,但不包含写入数据的语句
  • 触发器
  -- 触发器是与表有关的数据库对象,指在insert/update/delete之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端保持数据的完整性,日志记录,数据校验等操作。
  -- 使用别名OLD和NEW来引用触发器中发生的变化的记录内容,这与其他的数据库是相似的。现在触发器仅支持行级触发,不支持语句级触发
  -- 保证数据完整性、日志记录、数据校验
  
  -- 触发器类型
  INSERT型触发器:NEW表示将要或者已经新增的数据
  UPDATE型触发器:OLD表示修改之前的数据,NEW表示将要或已经修改后的数据
  DELETE型触发器:OLD表示将要或者已经删除的数据
  -- 语法
  -- 创建
  CREATE TRIGGER trigger_name
  BEFORE/ AFTER INSERT/ UPDATE/ DELETE ON table_name FOR EACH ROW -- 行级触发器
  BEGIN
      trigger_statement;
  END;
  -- 查看
  SHOW TRIGGER;
  -- 删除
  DROP TRIGGER [数据库名.]trigger_name;-- 没有指定数据库,默认为当前数据库

锁是计算机协调多个进程或线程并发访问某一资源的资质。

  • 全局锁
  -- 全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。
  -- 典型场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性
  flush tables with read lock; -- 加全局锁
  mysqldump -h远程ip -uroot -p密码 数据库 > 备份文件; -- 数据备份,mysqldump是MySQL的工具,不是SQL语句
  unlock tables; -- 释放全局锁
  -- 特点
  1、如果在主库上备份,那么在备份期间都不能执行更新,业务基本上停止。
  2、如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志,会导致主从延迟。
  在InnoDB引擎中,可以在备份时加 --single-transaction参数完成不加锁的一致性数据备份
  mysqldump --single--transaction -h远程ip -uroot -p密码 数据库 > 备份文件;
  • 表级锁
  -- 表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在myisam 、InnoDB、BDB引擎中。
  -- 表锁 分为两类 
  # 表共享读锁(read lock) 
  lock tables 表名...  read; -- 加锁
  unlock tables; /断开客户端连接 -- 释放锁
  # 表独占写锁(write lock)
  lock tables 表名...  write; -- 加锁
  unlock tables; /断开客户端连接 -- 释放锁
  -- 注意
  读锁不会组测其他客户端的读操作,但是会阻塞写。写锁会阻塞其他客户端的读操作,又会阻塞其他客户端的写操作。
  
  -- 元数据锁(meta data lock ,MDL)
  MDL加锁过程是系统自动控制,无序显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据一致性,在表上有活动事务时候,不可以对元数据进行写操作。为了避免DML与DDL冲突,保证读写的正确性。
  在MySQL5.5中引入MDL,当对一张表进行增删改查时,加MDL读锁(共享);对表结构进行变更操作时,加MDL写锁(排他)。
  -- 查看元数据锁
  select object_type,object_schema,object_name,lock_type,lock_duration from perfromance_schema.metadata_locks;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YWPIaUkt-1684318972567)(C:\Users\纪新想\AppData\Roaming\Typora\typora-user-images\image-20230517102148620.png)]

  -- 意向锁
  为了避免DML在执行时,加的行锁与表锁的冲突,在innoDB中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查
  # 意向共享锁(IS):由语句select...lock in share mode添加
  与表锁共享锁兼容,与表锁排他锁互斥
  # 意向排他锁(IX):由insert、update、delete、select..for update添加
  与表锁均互斥,意向锁之间不互斥
  -- 查看意向锁语句
  select object_type,object_schema,object_name,lock_type,lock_duration from perfromance_schema.data_locks;
  • 行级锁
  -- 行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高,应用在innoDB
  -- InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加锁。对于行级锁,主要分三类:
  1、行锁(record lock):锁定单个行记录,防止其他事务对此行进行updatedelete。在RC、RR隔离级别下都支持
  2、间隙锁(gap lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在该间隙insert,产生幻读。在RR隔离级别下都支持
  3、临键锁(next-key lock): 行锁与间隙锁的组合,同时锁住数据,并锁住数据前面的间隙。在RR隔离级别下都支持
  
  -- 行锁
  1、共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
  2、排他锁(X):允许获取其他排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁
  -- 注意
  默认情况下,InnoDBREPEATABLE READ事务隔离级别运行,InnoDB使用NEXT_KEY锁进行搜索和索引扫描,以防止幻读。
  1、针对唯一索引进行检索,对已存在的记录进行等值匹配时,将会自动优化为行锁
  2InnoDB的行锁是针对索引加的锁,不通过索引条件检索数据,那么引擎将对表中的所有记录加锁,此时就会升级为表锁
  -- 查看行锁语句
  select object_type,object_schema,object_name,lock_type,lock_duration from perfromance_schema.data_locks;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jssb85Bc-1684318972567)(C:\Users\纪新想\AppData\Roaming\Typora\typora-user-images\image-20230517105653790.png)]

  -- 间隙锁 /临键锁
  1、索引上的等值查询(唯一索引),给不存的记录加锁时,优化为间隙锁。
  2、索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,临键锁退化为间隙锁
  3、索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止
  -- 注意
  间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会组织另一个事务在同一间隙上采用间隙锁

InnoDB引擎

逻辑存储结构
  • 表空间(ibd文件),一个MySQL实例可以对应多个表空间,用于存储记录、索引等数据。
  • 段,分数据段(leaf node segment)、索引段(non-leaf node segment)、回滚段(rollback segment)、InnoDB是索引组织表,数据段就是B+树的叶子节点,索引段即为B+树的非叶子节点。段用来管理多个区。
  • 区,表空间的单元结构,每个区的大小为1M。默认情况下,存储引擎页大小为16K,一个区中有64个连续的页。
  • 页,存储引擎磁盘管理的最小单元,每个页的大小默认为16K。为保证页的连续性,存储引擎每次从磁盘申请4-5个区。
  • 行,存储引擎数据是按行进行存放的。
架构

在这里插入图片描述

内存架构
  • Buffer Pool :缓冲池是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若没有数据,从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘iIO,加快处理速度。

    缓冲池以页为单位,底层采用链表数据结构管理页。根据状态页分为三种类型:

    • free page: 空闲页,未被使用
    • liean page: 被使用的页,数据没有被修改过
    • dirty page: 脏页,被使用,数据被修改过,页中数据与磁盘的数据产生不一致
  • Change Buffer :更改缓冲区(针对非唯一二级索引页),在执行DML语句时,如果这些数据页没有在缓冲池中,不会直接操作磁盘,而会将数据变更存在更改缓冲区中,在未来数据被读取时,再将数据合并恢复到缓冲池中,最后将合并后的数据刷新到磁盘中。

    • 缓冲区的意义

      与聚集索引不同,二级索引通常时非唯一的,并且以相对随机的顺序插入二级索引。同样,删除和更新可能会影响索引树种不相邻的二级索引页,如果每一次操作磁盘,会造成大量的磁盘IO。有个缓冲区之后,可以在缓冲池合并处理,减少磁盘IO。

  • Adaptive Hash Index :自适应哈希索引,用于优化对缓冲池数据的查询。存储引擎会监控表上各索引页的查询,如果观察到哈希索引可以提升速度,则建立哈希索引。无需干涉,系统根据情况自动建立

    参数: adaptive_hash_index – 查看是否开启

  • Log Buffer :日志缓冲区,用来保存要写入磁盘中的日志数据(redo log、undo log),默认大小为16MB,日志缓冲区的日志会定期刷新到磁盘。如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘IO。

  innodb_log_buffer_size -- 缓冲区大小
  innodb_flush_log_at_trx_commit -- 日志刷新到磁盘时机 (0 1 2)
  -- 0 日志再每次事务提交时写入并刷新到磁盘
  -- 1 每秒将日志写入并刷新到磁盘一次
  -- 2 日志再每次提交事务后写入,并每秒刷新到磁盘一次
磁盘架构
  • System Tablespace :系统表空间时更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。
  innodb_data_file_path -- 表空间文件位置
  • File-Per-Table Tablespace :每个表的文件表空间包含单个存储引擎表的数据和索引,并存储在文件系统上的单个数据文件中。
  innodb_file_per_table -- 开关
  • General Tablespace :通用表空间,需要通过用户自己创建,在创建表时,可以指定该表空间。
  CREATE TABLESPACE space_name ADD DATAFILE 'file_name.ibd' ENGINE = InnoDB;
  -- 创建表时使用
  CREATE TABLE ...() TABLESPACE space_name;
  • Undo Tablespace :撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间,初始大小16M,用于存储undo log 日志。

  • Temporaty Tablespace :存储引擎会话临时表空间和全局临时表空间,存储用户创建的临时表等数据。

  • Doublewrite Buffer Files :双写缓冲区,存储引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常恢复数据。 xxx.dblwr文件

  • Redo Log :重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲以及重做日志文件,前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存放到该日志中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复。

后台线程
  • Master Thread :核心后台线程,负责调度其他线程,还负责将缓冲池中的数据异步刷新到磁盘中,保持数据一致性,还包括脏页的刷新、合并插入缓存、undo页回收。

  • IO Thread :存储引擎中使用了大量AIO来处理IO请求,极大化提高数据库性能,该线程主要负责IO请求的回调。

  Read thread -- 默认4个 ,负责读操作
  Write thread -- 默认4个,负责写操作 
  Log thread -- 默认1个,负责将日志缓冲区刷新到磁盘
  Insert buffer thread -- 默认1个,负责将写缓冲区内容刷新到磁盘 
  • Purge Thread :主要用于回收事务已经提交的undo log,在事务提交之后,undo log可能不用了,就用该线程回收。

  • Page Cleaner Thread:协助核心后台线程刷新脏页到磁盘的线程,它可以减轻Master Thread的工作压力,减少阻塞。

事务原理

  • redo log 和undo log
-- 保证了数据的持久性、一致性和原子性
Redo Log :重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲以及重做日志文件,前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存放到该日志中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复。
Undo log :回滚日志,用于记录数据被修复前的信息,作用包含两个:提供回滚和MVCC(多版本并发控制)
undo log与redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。当执行roolback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
undo log销毁:在事务执行时发生,事务提交时,并不会立即删除undo log,因为这些日志可能用于MVCC
undo log存储:undo log采用段的方式进行管理和记录,存放在前面介绍的rollback segment回滚段中,包含1024个undo log segment。
-- 锁和MVCC保证了隔离性

MVCC

  • 当前读

读取的时记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。如:

select...lock in share mode(共享锁)select...for updateupdateinsertdelete(排他锁)都是一种当前读。
  • 快照读

简单的select(不加锁)就是快照读,读取的时记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

Read Committed : 每次select,都生成一个快照读。
Repeatable Read : 开启事务后第一个select语句才是快照读的地方。
Serializable : 快照读会退化为当前读
  • MVCC

全称Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖与数据库记录的三个隐式字段、undo log、readView。

  • 隐藏字段
DB_TRX_ID :最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID
DB_ROLL_PTR :回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本
DB_ROW_ID : 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段
  • undo log
insert时候,产生的日志旨在回滚时需要,在事务提交后,可被立即删除。
当 updatedelete时候,产生的 undo log日志不仅在回滚时需要,在快照读时也需要,不会被立即删除
-- undo log版本连
不同事务或相同事务对同一条记录进行修改,会导致记录的日志生成一条记录版本链表,链表头部是最近的旧记录,链表尾部是最早的旧记录
  • readView
-- 读视图是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。
m_ids: 当前活跃的事务ID集合 
min_trx_id: 最小活跃事务
max_trx_id: 预分配事务ID,当前最大事务ID+1(因为事务ID时自增的)
creator_trx_id: 读视图创建者的事务ID

在这里插入图片描述

-- 不同隔离级别,生成ReadView的时机不同:
READ COMMITTED : 在事务中每一次执行快照读时生成读视图
REPEATABLE READ :仅在事务中第一次执行快照读时生成读视图,后续复用该读视图
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值