专栏学习-MySQL实战45讲(三)

本文是个人学习极客时间专栏《MySQL实战45讲》过程中所记录的一些笔记,内容来源于专栏

MySQL高可用

主备延迟

在备库上执行 show slave status 命令,它的返回结果里面会显示 seconds_behind_master,用于表示当前备库延迟了多少秒。主备延迟的来源可能

  • 备库所在机器的性能要比主库所在的机器性能差

  • 备库的压力大

  • 大事务,如一次性地用 delete 删除太多数据,大表 DDL 等

主备切换策略

  • 可靠性优先策略(有不可用时间)

    • 判断备库 B 现在的 seconds_behind_master,如果小于某个值(比如 5 秒)继续下一步,否则持续重试这一步;

    • 把主库 A 改成只读状态,即把 readonly 设置为 true;

    • 判断备库 B 的 seconds_behind_master 的值,直到这个值变成 0 为止;

    • 把备库 B 改成可读写状态,也就是把 readonly 设置为 false;

    • 把业务请求切到备库 B。

  • 可用性优先策略(有可能出现数据不一致)

    • 不等主备数据同步,直接把连接切到备库 B,并且让备库 B 可以读写

MySQL Join

Index Nested-Loop Join

  • **可以用上被驱动表的索引。**先遍历驱动表(全表扫描),然后从驱动表中取出每行数据中的关联值,去被驱动表中查找满足条件的记录(树搜索)

Block Nested-Loop Join

  • 被驱动表上无索引可用。把驱动表的数据读入线程内存 join_buffer 中(全表扫描,存不下则分段取),把被驱动表的每一行取出来(全表扫描),跟 join_buffer 中的数据做对比,满足 join 条件的,作为结果集的一部分返回

Join 该怎么用

  • 能不能使用 join 语句?

    • 如果可以使用 Index Nested-Loop Join 算法,也就是说可以用上被驱动表上的索引,其实是没问题的

    • 如果使用 Block Nested-Loop Join 算法,扫描行数就会过多。尤其是在大表上的 join 操作,这样可能要扫描被驱动表很多次,会占用大量的系统资源。所以这种 join 尽量不要用

  • 如果要使用 join,应该选择大表做驱动表还是选择小表做驱动表?

    • 总是应该使用小表做驱动表(在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与 join 的各个字段的总数据量,数据量小的那个表,就是“小表”,应该作为驱动表

常见配置参数

  • join_buffer_size:控制Join Buffer的大小,调大后可以避免多次的被驱动表扫描,从而提高性能。默认值为257KB

自增主键为什么不是连续的

自增值保存在哪

  • MyISAM 引擎的自增值保存在数据文件中

  • InnoDB 引擎的自增值,其实是保存在了内存里,并且到了 MySQL 8.0 版本后,才有了“自增值持久化”的能力

    • 在 MySQL 5.7 及之前的版本,自增值保存在内存里,并没有持久化。每次重启后,第一次打开表的时候,都会去找自增值的最大值 max(id),然后将 max(id)+1 作为这个表当前的自增值

    • 在 MySQL 8.0 版本,将自增值的变更记录在了 redo log 中,重启的时候依靠 redo log 恢复重启之前的值

自增值修改机制

假设,某次要插入的值是 X,当前的自增值是 Y

  • 如果 X < Y,那么这个表的自增值不变;

  • 如果 X ≥ Y,那么需要把当前自增值修改为新的自增值

新的自增值生成算法是:从 auto_increment_offset 开始,以 auto_increment_increment 为步长,持续叠加,直到找到第一个大于 X 的值,作为新的自增值。其中,auto_increment_offset 和 auto_increment_increment 是两个系统参数,分别用来表示自增的初始值步长,默认值都是 1

自增值修改时机

  • 表的自增值修改是在真正执行插入数据的操作之前,且自增值不会回退(MySQL 这么设计是为了提升性能,回退需要多一次判断id存不存在或需要扩大自增id锁的范围),所以如果插入数据操作失败(如唯一键冲突)或事务回滚,那么自增主键将出现不连续的情况(但是递增的)

自增主键不连续的原因

  • 数据插入时发生唯一索引冲突

  • 数据插入事务回滚

  • 自增主键的批量申请。对于批量插入语句(如 insert … select、replace … select、load data 语句),MySQL 有一个批量申请自增 id 的策略,第一次申请分配1个自增id,后续每次申请的 id 都是上一次的两倍,当 id 用不到时会浪费掉

加载评论