面试八股文 mysql篇 持续更新~

mysql面试的八股文,持续更新

连接器的最大连接数以及调优

mysql服务器最大支持max_connect 为 16384

根据需求来看,一般2核4G机器填写1000,16核64G填写5000。

刷脏页 参数

innodb_io_capacity 表示磁盘的io能力,控制了刷脏页的速度

innodb_max_dirty_pages_pct 脏页比例阈值,达到这个值就开始刷脏页

脏页比例计算 Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total

redolog和binlog区别

  • redolog innodb存储层,binlog server层
  • redolog 是物理日志,记录的语句在内存中执行了什么动作,binlog是逻辑日志,记录了语句的原始逻辑
  • 先写内存,再写redolog prepare 再写binlog 再写redolog commit

redolog和binlog 刷盘参数

控制binlog 把binlog cache 刷到磁盘的时机:sync_binlog

  • sync_binlog=0 的时候,表示每次提交事务都只 write,不 fsync;
  • sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;
  • sync_binlog=N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。

binlog 组提交优化参数:binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count

控制redolog把logbuffer 写入 oscache 和刷盘的时机: innodb_flush_log_at_trx_commit

  • 设置为 0 的时候,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;
  • 设置为 1 的时候,表示每次事务提交时都将 redo log 直接持久化到磁盘;
  • 设置为 2 的时候,表示每次事务提交时都只是把 redo log 写到 page cache。

undolog

mysql如何保证acid

MySQL 作为一个关系型数据库,以最常见的 InnoDB 引擎来说,是如何保证 ACID 的。

  • (Atomicity原子性: 事务是最小的执行单位,不允许分割。原子性确保动作要么全部完成,要么完全不起作用;
  • (Consistency)一致性: 执行事务前后,数据保持一致;
  • (Isolation)隔离性: 并发访问数据库时,一个事务不被其他事务所干扰。
  • (Durability)持久性: 一个事务被提交之后。对数据库中数据的改变是持久的,即使数据库发生故障。

如何保证

  • 原子性:undo log,要不执行成功,要不执行失败
  • 一致性:事务,也需要应用层面进行维护
  • 隔离性:隔离级别
  • 持久性:redo log

sql执行流程

  • 连接器,权限校验,连接池
  • 查询缓存,直接返回
  • 分析器,分析语法语义是否合规,正确
  • 优化器,优化sql,选择合适索引
  • 执行器,调用存储引擎api,执行语句,要什么,存储引擎给什么
  • 存储引擎,从内存和磁盘中找到sql执行结果,返回执行器

mvcc

  • 使用一致性视图和undolog实现,数据版本的可见性规则,就是基于数据的 row trx_id 和这个一致性视图的对比结果得到的。

  • 用begin开始事务,并不会第一时间创建一致性视图,而且等第一个sql语句执行才会创建(可以用start transaction with consistent snapshot)

  • 不同隔离等级下(mvcc只支持RR、RC),创建视图的时间不一样

    • 可重复度RR下,是事务开始的时候创建一致性视图
    • 读提交RC下,是每个sql语句执行前都会重新创建一致性视图

一致性视图:

InnoDB 为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务 ID。“活跃”指的就是,启动了但还没提交。

根据数据的row trx_id 和一致性视图判断是否可见

img

undolog:

三个虚线箭头,就是 undo log;

而 V1、V2、V3 并不是物理上真实存在的,而是每次需要的时候根据当前版本和 undo log 计算出来的。比如,需要 V2 的时候,就是通过 V4 依次执行 U3、U2 算出来。

具体的执行过程,是根据当前一致性视图去查undolog,回滚日志到当前事务id可见的版本

img

当前读:

更新语句执行都是先读后写,而且这个读是读当前数据的最近值,被称作“当前度”

分析过程示例:

[]中的是是一致性视图,()中的是当前事务id,最右边的是undolog

img

无法修改数据的场景(mvcc)

# 表结构和数据
mysql> CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
insert into t(id, c) values(1,1),(2,2),(3,3),(4,4);
img

无法修改的原因:“当前读”引起

解决办法:重试或者根据主键id去修改

mha

两阶段锁协议

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。

为什么要用b+tree,其他可以用的数据结构都有哪些

索引的常用数据结构

  1. 二叉树
  2. 红黑树 红黑树是一种特化的 AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡;若一棵二叉查找树是红黑树,则它的任一子树必为红黑树。
  3. Hash 表
  4. B-tree 是一颗绝对平衡的多路树,针对红黑树优化了树高,mongodb使用b-tree
  5. B+tree

为什么不是用其他数据结构

  • 二叉树
    • 对于递增的数据不适合当索引
  • 红黑树
    • 对是属于平衡二叉树的红黑树来说,数据量大的时候,树高就很高,查找的过程会产生很多随机io
  • hash表
    • 不适合范围查询

b-tree和b+tree区别和特点

b-tree

  1. B-tree 主要用于文件系统以及部分数据库索引,例如:MongoDB。

  2. 从查找效率考虑一般要求 B-tree 的阶数 m ≥ 3

  3. B-tree 上算法的执行时间主要由读、写磁盘的次数来决定,故一次I/O操作应读写尽可能多的信息。

    因此 B-tree 的节点规模一般以一个磁盘页为单位。一个结点包含的关键字及其孩子个数取决于磁盘页的大小。

b+tree

  1. 单个节点存储越多的元素,自然在整个过程中的磁盘💽I/O交互就越少;
  2. 相对 B-tree 来说,所有的查询最终都会找到叶子节点,这也是 B+tree 性能稳定的一个体现;
  3. 所有叶子节点通过双向链表相连,范围查询非常方便,这也是 B+tree 最明显的优势。

区别

  1. 所有的子节点,一定会出现在叶子节点上

  2. 相邻的叶子节点之间,会用一个双向链表连接起来(关键)

  3. 非叶子节点只存储索引,不存储数据,就为放更多索引

    • 相比 B-tree 来说,进行范围查找时只需要查找两个节点,进行遍历就行。而 B-tree 需要获取所有节点,相比之下 B+tree 效率更高。

说一说三大范式

  • 「第一范式」:数据库中的字段具有**「原子性」**,不可再分,并且是单一职责
  • 「第二范式」「建立在第一范式的基础上」,第二范式要求数据库表中的每个实例或行必须**「可以被惟一地区分」**。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主键
  • 「第三范式」「建立在第一,第二范式的基础上」,确保每列都和主键列直接相关,而不是间接相关不存在其他表的非主键信息

但是在我们的日常开发当中,「并不是所有的表一定要满足三大范式」,有时候冗余几个字段可以少关联几张表,带来的查询效率的提升有可能是质变的

MyISAM 与 InnoDB 的区别是什么?

e42a8e4a50675fbe6540fb3558986add.png
  • 「InnoDB支持事务,MyISAM不支持」

  • 「InnoDB 支持外键,而 MyISAM 不支持」

  • 「InnoDB是聚集索引」,使用B+Tree作为索引结构,数据文件是和索引绑在一起的,必须要有主键。「MyISAM是非聚集索引」,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

  • 「InnoDB 不保存表的具体行数」「MyISAM 用一个变量保存了整个表的行数」

  • Innodb 有 「redolog」 日志文件,MyISAM 没有

  • 「Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI」

  • Innodb:frm是表定义文件,ibd是数据文件
  • Myisam:frm是表定义文件,myd是数据文件,myi是索引文件
  • 「InnoDB 支持表、行锁,而 MyISAM 支持表级锁」
  • 「InnoDB 必须有唯一索引(主键)」,如果没有指定的话 InnoDB 会自己生成一个隐藏列Row_id来充当默认主键,「MyISAM 可以没有」*

为什么推荐使用自增 id 作为主键?

69a8346941af33b8ceded3fcafe0ce03.png
  • 1.普通索引的 B+ 树上存放的是主键索引的值,如果该值较大,会**「导致普通索引的存储空间较大」**
  • 2.使用自增 id 做主键索引新插入数据只要放在该页的最尾端就可以,直接**「按照顺序插入」**,不用刻意维护
  • 3.页分裂容易维护,当插入数据的当前页快满时,会发生页分裂的现象,如果主键索引不为自增 id,那么数据就可能从页的中间插入,页的数据会频繁的变动,「导致页分裂维护成本较高」

一条查询语句是怎么执行的?

eb4e297a05891f2cdcfd9990f89e483a.png
  • 通过连接器跟客户端**「建立连接」**
  • 通过查询**「缓存查询」**之前是否有查询过该 sql
    • 有则直接返回结果
    • 没有则执行第三步
  • 通过分析器**「分析该 sql 的语义」**是否正确,包括格式,表等等
  • 通过优化器**「优化该语句」**,比如选择索引,join 表的连接顺序
  • 「验证权限」,验证是否有该表的查询权限
    • 没有则返回无权限的错误
    • 有则执行第六步
  • 通过执行器调用存储引擎执行该 sql,然后返回**「执行结果」**

使用 Innodb 的情况下,一条更新语句是怎么执行的?

用以下语句来举例,c 字段无索引,id 为主键索引(无其他索引,有普通索引和唯一索引情况会发生变化,有了change buffer/insert buffer的优化)

update T set c=c+1 where id=2;
  • 执行器先找引擎取 id=2 这一行。id 是主键,引擎直接用树搜索找到这一行
    • 如果 id=2 这一行所在的数据页本来就**「在内存中」,就「直接返回」**给执行器
    • 「不在内存」中,需要先从磁盘「读入内存」,然后再**「返回」**
  • 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口**「写入这行新数据」**
  • 擎将这行新数据更新到内存中,同时将这个更新操作**「记录到 redo log 里面」**,此时 redo log 处于 「prepare」 状态。然后告知执行器执行完成了,随时可以提交事务
  • 执行器**「生成这个操作的 binlog」**,并把 binlog 「写入磁盘」
  • 执行器调用引擎的**「提交事务」接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,「更新完成」**

Innodb 事务为什么要两阶段提交?

目的:保持redolog和binlog的状态一致性,进而保证了主从一致性

  • 先写 redolog 后写binlog。假设在 redolog 写完,binlog 还没有写完的时候,MySQL 进程异常重启,这时候 binlog 里面就没有记录这个语句。然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 「binlog 丢失」,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。
  • 先写 binlog 后写 redolog。如果在 binlog 写完之后 crash,由于 redolog 还没写,崩溃恢复以后这个事务无效,所以这一行c的值是0。但是 binlog 里面已经记录了“把c从0改成1”这个日志。所以,在之后用 binlog 来恢复的时候就**「多了一个事务出来」**,恢复出来的这一行 c 的值就是 1,与原库的值不同。

可以看到,「如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致」

什么是索引?

相信大家小时候学习汉字的时候都会查字典,想想你查字典的步骤,我们是通过汉字的首字母 a~z 一个一个在字典目录中查找,最终找到该字的页数。想想,如果没有目录会怎么样,最差的结果是你有可能翻到字典的最后一页才找到你想要找的字。

索引就**「相当于我们字典中的目录」**,可以极大的提高我们在数据库的查询效率。

索引失效的场景有哪些?

以下随便列举几个,不同版本的 mysql 场景不一

  • 最左前缀法则(带头索引不能死,中间索引不能断)
  • 不要在索引上做任何操作(计算、函数、自动/手动类型转换),不然会导致索引失效而转向全表扫描
  • 不能继续使用索引中范围条件(bettween、<、>、in等)右边的列,如:
select a from user where c > 5 and b = 4
  • 索引字段上使用(!= 或者 < >)判断时,会导致索引失效而转向全表扫描
  • 索引字段上使用 is null / is not null 判断时,会导致索引失效而转向全表扫描。
  • 索引字段使用like以通配符开头(‘%字符串’)时,会导致索引失效而转向全表扫描,也是最左前缀原则。
  • 索引字段是字符串,但查询时不加单引号,会导致索引失效而转向全表扫描
  • 索引字段使用 or 时,会导致索引失效而转向全表扫描

为什么采用 B+ 树,而不是 B-树

B+ 树只在叶子结点储存数据,非叶子结点不存具体数据,只存 key,查询更稳定,增大了广度,而一个节点就是磁盘一个内存页,内存页大小固定,那么相比 B 树,B- 树这些**「可以存更多的索引结点」**,宽度更大,树高矮,节点小,拉取一次数据的磁盘 IO 次数少,并且 B+ 树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,效率更高。

WAl 是什么?有什么好处?

先写日志,在写磁盘

WAL 就是 Write-Ahead Logging,其实就是**「所有的修改都先被写入到日志中,然后再写磁盘」**,用于保证数据操作的原子性和持久性。

好处:

  • 「读和写可以完全地并发执行」,不会互相阻塞
  • 先写入 log 中,磁盘写入从**「随机写变为顺序写」**,降低了 client 端的延迟就。并且,由于顺序写入大概率是在一个磁盘块内,这样产生的 io 次数也大大降低
  • 写入日志当数据库崩溃的时候**「可以使用日志来恢复磁盘数据」**

什么是回表?

b7ac1234b2d44d81bf17dee1c95d4d37.png

回表就是先通过数据库索引扫描出该索引树中数据所在的行,取到主键 id,再通过主键 id 取出主键索引数中的数据,即基于非主键索引的查询需要多扫描一棵索引树.

什么是索引下推?

如果存在某些被索引的列的判断条件时,MySQL 将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合 MySQL 服务器传递的条件,「只有当索引符合条件时才会将数据检索出来返回给 MySQL 服务器」

就是一般情况下,索引列中存在的字段,并且存在where 判断,都可以被利用到,无论是否满足索引使用规则

什么是覆盖索引?

覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取,可以减少回表的次数。比如:

select id from t where age = 1;

id 为主键索引,age 为普通索引,age 这个索引树存储的就是逐渐信息,可以直接返回

什么是最左前缀原则?

最左前缀其实说的是,在 where 条件中出现的字段,「如果只有组合索引中的部分列,则这部分列的触发索引顺序」,是按照定义索引的时候的顺序从前到后触发,最左面一个列触发不了,之后的所有列索引都无法触发。

比如**「有一个 (a,b,c) 的组合索引」**

where a = 1 and b = 1

此时 a,b 会命中该组合索引

where a = 1 and c = 1

此时 a 会命中该组合索引, c 不会

where b = 1 and c = 1

此时不会命中该组合索引

普通索引和唯一索引该怎么选择?

  • 查询
    • 当普通索引为条件时查询到数据会一直扫描,直到扫到不同的值
    • 当唯一索引为查询条件时,查到该数据会直接返回,不会继续扫表
  • 更新
    • 普通索引会直接将操作更新到 change buffer 中,然后结束
    • 唯一索引需要判断数据是否冲突,不能使用change buffer

适合场景:

  • 普通索引适合读多写少的情况,尤其是在写完,立马就读的场景是不能使用的(原因是会增加changebuffer 的维护成本)
  • 一般不建议使用唯一索引

什么是事务?其特性是什么?

事务是指是程序中一系列操作必须全部成功完成,有一个失败则全部失败。

6d4384f30d148e586ee353b97e1f0fef.png

特性

  • 「1.原子性(Atomicity)」:要么全部执行成功,要么全部不执行。
  • 「2.一致性(Consistency)」:事务前后数据的完整性必须保持一致。
  • 「3.隔离性(Isolation)」:隔离性是当多个事务同事触发时,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  • 「4.持久性(Durability)」:事务完成之后的改变是永久的。

事务的隔离级别?

  • 1.「读提交」:即能够**「读取到那些已经提交」**的数据
  • 2.「读未提交」:即能够**「读取到没有被提交」**的数据
  • 3.「可重复读」:可重复读指的是在一个事务内,最开始读到的数据和事务结束前的**「任意时刻读到的同一批数据都是一致的」**
  • 4.「可串行化」:最高事务隔离级别,不管多少事务,都是**「依次按序一个一个执行」**
875a4a8184a2eccf33ca1176799d540a.png
  • 「脏读」
    • 脏读指的是**「读到了其他事务未提交的数据」**,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读
  • 「不可重复读」
    • 对比可重复读,不可重复读指的是在同一事务内,「不同的时刻读到的同一批数据可能是不一样的」
  • 「幻读」
    • 幻读是针对数据插入(INSERT)操作来说的。假设事务A对某些行的内容作了更改,但是还未提交,此时事务B插入了与事务A更改前的记录相同的记录行,并且在事务A提交之前先提交了,而这时,在事务A中查询,会发现**「好像刚刚的更改对于某些数据未起作用」**,但其实是事务B刚插入进来的这就叫幻读

binlog 是做什么的?

binlog 是归档日志,属于 Server 层的日志,是一个二进制格式的文件,用于**「记录用户对数据库更新的SQL语句信息」**。

主要作用

  • 主从复制
  • 数据恢复

undolog 是做什么的?

undolog 是 InnoDB 存储引擎的日志,用于保证数据的原子性,「保存了事务发生之前的数据的一个版本,也就是说记录的是数据是修改之前的数据,可以用于回滚」,同时可以提供多版本并发控制下的读(MVCC)。

主要作用

  • 事务回滚
  • 实现多版本控制(MVCC)

relaylog 是做什么的?

relaylog 是中继日志,「在主从同步的时候使用到」,它是一个中介临时的日志文件,用于存储从master节点同步过来的binlog日志内容。

682ebc9c026cc8b81bc74ca0115f79df.png

master 主节点的 binlog 传到 slave 从节点后,被写入 relay log 里,从节点的 slave sql 线程从 relaylog 里读取日志然后应用到 slave 从节点本地。从服务器 I/O 线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后 SQL 线程会读取 relay-log 日志的内容并应用到从服务器,从而**「使从服务器和主服务器的数据保持一致」**。

redolog 是做什么的?

redolog 是 「InnoDB 存储引擎所特有的一种日志」,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。

可以做**「数据恢复并且提供 crash-safe 能力」**

当有增删改相关的操作时,会先记录到 Innodb 中,并修改缓存页中的数据,「等到 mysql 闲下来的时候才会真正的将 redolog 中的数据写入到磁盘当中」

redolog 是怎么记录日志的?

9b9820761e6fc6d9b2644f70fea0c878.png

InnoDB 的 redo log 是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB,那么总共就可以记录4GB的操作。「从头开始写,写到末尾就又回到开头循环写」

所以,如果数据写满了但是还没有来得及将数据真正的刷入磁盘当中,那么就会发生**「内存抖动」**现象,从肉眼的角度来观察会发现 mysql 会宕机一会儿,此时就是正在刷盘了。

redolog 和 binlog 的区别是什么?

b83959086f28bb82d5dd174a12af8bdc.png
  • 「redolog」「Innodb」 独有的日志,而 「binlog」「server」 层的,所有的存储引擎都有使用到
  • 「redolog」 记录了**「具体的数值」,对某个页做了什么修改,「binlog」** 记录的**「操作内容」**
  • 「binlog」 大小达到上限或者 flush log 「会生成一个新的文件」,而 「redolog」 有固定大小**「只能循环利用」**
  • 「binlog 日志没有 crash-safe 的能力」,只能用于归档。而 redo log 有 crash-safe 能力。
  • binlog 是server 层,redolog 是存储层

说一说 mvcc 吧,有什么作用?

MVCC:多版本并发控制,是现代数据库(包括 MySQL、Oracle、PostgreSQL 等)引擎实现中常用的处理读写冲突的手段,目的在于**「提高数据库高并发场景下的吞吐性能」**。

在 MVCC 协议下,每个读操作会看到一个一致性的快照,「这个快照是基于整个库的」,并且可以实现非阻塞的读,用于**「支持读提交和可重复读隔离级别的实现」**。

MVCC 允许数据具有多个版本,这个版本可以是时间戳或者是全局递增的事务 ID,在同一个时间点,不同的事务看到的数据是不同的,这个修改的数据是**「记录在 undolog 中」**的。

一条 Sql 语句查询一直慢会是什么原因?

d52351ca45402fd46125dc2e59be0a76.png
  • 「1.没有用到索引」
    • 比如函数导致的索引失效,或者本身就没有加索引
  • 「2.表数据量太大」
    • 考虑分库分表吧
  • 「3.优化器选错了索引」
    • 「考虑使用」 force index 强制走索引

一条 Sql 语句查询偶尔慢会是什么原因?

bd6876ff641aba17165df1c7ef249df5.png
  • 「1. 数据库在刷新脏页」
    • 比如 「redolog 写满了」,**「内存不够用了」**释放内存如果是脏页也需要刷,mysql 「正常空闲状态刷脏页」
  • 「2. 没有拿到锁」

Mysql 主从之间是怎么同步数据的?

  • 1.master 主库将此次更新的事件类型**「写入到主库的 binlog 文件」**中
  • 2.master 「创建 log dump 线程通知 slave」 需要更新数据
  • 3.「slave」 向 master 节点发送请求,「将该 binlog 文件内容存到本地的 relaylog 中」
  • 4.「slave 开启 sql 线程」读取 relaylog 中的内容,「将其中的内容在本地重新执行一遍」,完成主从数据同步
fae385cd4a137a82e28b52c9eb9737a5.png

「同步策略」

  • 1.「全同步复制」:主库强制同步日志到从库,等全部从库执行完才返回客户端,性能差
  • 2.「半同步复制」:主库收到至少一个从库确认就认为操作成功,从库写入日志成功返回ack确认

主从延迟要怎么解决?

  • 1.MySQL 5.6 版本以后,提供了一种**「并行复制」**的方式,通过将 SQL 线程转换为多个 work 线程来进行重放
  • 2.「提高机器配置」(王道)
  • 3.在业务初期就选择合适的分库、分表策略,**「避免单表单库过大」**带来额外的复制压力
  • 4.「避免长事务」
  • 5.「避免让数据库进行各种大量运算」
  • 6.对于一些对延迟很敏感的业务**「直接使用主库读」**

删除表数据后表的大小却没有变动,这是为什么?

在使用 delete 删除数据时,其实对应的数据行并不是真正的删除,是**「逻辑删除」,InnoDB 仅仅是将其「标记成可复用的状态」**,所以表空间不会变小

为什么 VarChar 建议不要超过255?

e7172b78774dcb6d1679d262491d3a32.png

innodb索引列最大长度不能超过767byte,等同于utf8mb4编码下,前缀索引列不能超过191,可以通过innodb_large_prefix参数修改+修改行格式来变大

分布式式事务怎么实现?

  • 1.「本地消息表」
  • 2.「消息事务」
  • 3.「二阶段提交」
  • 4.「三阶段提交」
  • 5.「TCC」
  • 6.「最大努力通知」
  • 7.「Seata 框架」

七种分布式事务的解决方案,一次讲给你听

Mysql 中有哪些锁?

以下并不全,主要理解下锁的意义即可

  • 基于锁的属性分类:共享锁、排他锁
  • 基于锁的粒度分类:表锁、行锁、记录锁、间隙锁、临键锁
  • 基于锁的状态分类:意向共享锁、意向排它锁、死锁

为什么不要使用长事务?

5cca8dadf562adaf140437cf95001d59.png
  • 1.并发情况下,数据库**「连接池容易被撑爆」**
  • 2.「容易造成大量的阻塞和锁超时」
    • 长事务还占用锁资源,也可能拖垮整个库,
  • 3.执行时间长,容易造成**「主从延迟」**
  • 4.「回滚所需要的时间比较长」
    • 事务越长整个时间段内的事务也就越多
  • 5.「undolog 日志越来越大」
    • 长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

buffer pool 是做什么的?

buffer pool 是一块内存区域,为了**「提高数据库的性能」**,当数据库操作数据的时候,把硬盘上的数据加载到 buffer pool,不直接和硬盘打交道,操作的是 buffer pool 里面的数据,数据库的增删改查都是在 buffer pool 上进行

buffer pool 里面缓存的数据内容也是一个个数据页

其中**「有三大双向链表」**:

  • 「free 链表」
    • 用于帮助我们找到空闲的缓存页
  • 「flush 链表」
    • 用于找到脏缓存页,也就是需要刷盘的缓存页
  • 「lru 链表」
    • 用来淘汰不常被访问的缓存页,分为热数据区和冷数据区,冷数据区主要存放那些不常被用到的数据

预读机制:

  • Buffer Pool 有一项特技叫预读,存储引擎的接口在被 Server 层调用时,会在响应的同时进行预判,将下次可能用到的数据和索引加载到 Buffer Pool

说说你的 Sql 调优思路吧

e6d0dffc2b67df74c5ebc558dcb3e9ff.png
  • 1.「表结构优化」
    • 1.1拆分字段
    • 1.2字段类型的选择
    • 1.3字段类型大小的限制
    • 1.4合理的增加冗余字段
    • 1.5新建字段一定要有默认值
  • 2.「索引方面」
    • 2.1索引字段的选择
    • 2.2利用好mysql支持的索引下推,覆盖索引等功能
    • 2.3唯一索引和普通索引的选择
  • 3.「查询语句方面」
    • 3.1避免索引失效
    • 3.2合理的书写where条件字段顺序
    • 3.3小表驱动大表
    • 3.4可以使用force index()防止优化器选错索引
  • 4.「分库分表」

innodb的三大特性

change buffer

在这里插入图片描述

change buffer是buffer pool中单独的一个空间,数据页变更时,如果数据在内存中,则直接修改,否则把变更操作记录到change buffer,读数据的时候会把数据从磁盘中度处理,然后应用change buffer ,返回

与redo log的关系:

使用change buffer的时候,也需要在redolog中记录动作

使用条件:

  • 变更二级索引
  • 变更非唯一性索引

作用:

提升了dml操作的性能,其中redolog节省了随机写;change buffer节省了随机读

查看change buffer: show engine innodb status;

double write

脏页刷盘的过程中存在风险,比如进程退出、宕机、掉电,会出现部分写失效而导致数据丢失的情况,比如数据库正在写一个页面,而这个页只写了一部分(比如16K的页,只写前4K的页)的情况,因为redolog记录的是页的物理变更,但是现在物理页已经不完整,使用重做日志是无效的。

而 double write可以解决这个问题,即保证数据页的安全性,

工作流程:

在这里插入图片描述

1、当一系列机制触发数据缓冲池中的脏页刷新时,并不直接写入磁盘数据文件中,而是先把脏页拷贝至内存中的doublewrite buffer中;

2、接着从两次写缓冲区分两次写入磁盘共享表空间中(连续存储,顺序写,性能很高),每次写1MB;

3、待第二步完成后,再将doublewrite buffer中的脏页数据写入实际的各个表空间文件(离散写);(脏页数据固化后,即进行标记对应doublewrite数据可覆盖)

恢复

自适应hash索引adaptive hash index

innodb 索引使用的是b+数,引擎会监控二级索引的使用情况,如果发现请求频发,会把索引升级为热数据,建立hash索引来提高速度,这个过程是引擎自己决策,无法干预。

默认开启

参数:innodb_adaptive_hash_index

查看使用情况:show engine innodb status;

优点:

  • 无序,没有树高,查询快
  • 降低对二级索引数的访问
  • 自适应

缺点:

  • 会占用innodb buffer pool;
  • 只适合等值查询
  • 自适应
  • 不能用于排序

如何优化io瓶颈

  • 组提交,根据binlog_group_commit_sync_delay 和binlog_group_commit_sync_no_delay_count 参数,减少binlog写盘次数

当前读和一致性读

一致性读: MySQL中读取数据的时候总是一致性读:事务开始前会创建一个一致性视图,在事务执行过程中,所有其他未提交或者已经提交的事务,对当前已经开启的事务不可见。用于mvcc

当前读:更新数据的时候,会执行当前读:意思是在更新之前会去数据库中获取最新的已经提交的事务数据内容,然后基于已经提交的事务的基础上更新自己的内容,要加锁。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我想骑车

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值