抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

逻辑架构

MySQL 可以分为 Server 层和存储引擎层两部分。

  1. Server层
    • 连接器: 负责跟客户端建立连接、获取权限、维持和管理连接
    • 查询缓存: 命中缓存直接返回(不推荐,MySQL 8.0已删除缓存模块)
    • 分析器:对SQL语句做解析,词法分析->语法分析
    • 优化器:优化SQL,优化索引
    • 执行器:执行SQL语句
  2. 存储引擎层
    负责数据的存储和提取

日志系统

重要的日志模块: redo log(重做日志)、binlog(归档日志)、undo log(回滚日志)

redo log

  • 内容:物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。

  • 作用:防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,确保事务的持久性。

  • 产生条件:事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。

  • 释放条件:当对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。

  • 对应的物理文件:

    默认情况下,对应的物理文件位于数据库的data目录下的ib_logfile1&ib_logfile2

    innodb_log_group_home_dir 指定日志文件组所在的路径,默认./ ,表示在数据库的数据目录下。

    innodb_log_files_in_group 指定重做日志文件组中文件的数量,默认2。

    关于文件的大小和数量,由以下两个参数配置:

    innodb_log_file_size 重做日志文件的大小。

    innodb_mirrored_log_groups 指定了日志镜像文件组的数量,默认1

  • 写入时机:redo log是什么时候写盘的?在事物开始之后逐步写盘的。

    重做日志有一个缓存区Innodb_log_buffer(默认大小为8M),Innodb存储引擎先将重做日志写入innodb_log_buffer中。

    然后会通过以下三种方式将innodb日志缓冲区的日志刷新到磁盘:

    1. Master Thread 每秒一次执行刷新Innodb_log_buffer到重做日志文件。
    2. 每个事务提交时会将重做日志刷新到重做日志文件。
    3. 当重做日志缓存可用空间 少于一半时,重做日志缓存被刷新到重做日志文件
  • 其他:

    1. redolog是存储引擎InnoDB特有的日志。

    2. 使用WAL(Write-Ahead Logging)技术:即先写日志,再写磁盘。可以将数据库将随机写转换成了顺序写,大大提升了数据库的性能。

    3. crash-safe能力:保证即使数据库发生异常重启,之前提交的记录都不会丢失。

    4. 参数innodb_flush_log_at_trx_commit可以控制redo log的写入策略:

      (1) 设置为 0 的时候,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;

      (2) 设置为 1 的时候,表示每次事务提交时都将 redo log 直接持久化到磁盘;

      (3) 设置为 2 的时候,表示每次事务提交时都只是把 redo log 写到 page cache。

binlog

  • 内容:server层逻辑格式的二进制日志,主要是用来记录对mysql数据更新或潜在发生更新的SQL语句。
  • 作用:
    1. 用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
    2. 用于数据库的基于时间点的还原。
  • 产生条件:事务提交的时候,一次性将事务中的sql语句按照一定的格式记录到binlog中(先写binlog cache,事务提交再写到binlog)。
  • 释放条件:binlog的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除。
  • 对应的物理文件:配置文件的路径为log_bin_basename,binlog日志文件按照指定大小,当日志文件达到指定的最大的大小之后,进行滚动更新,生成新的日志文件。对于每个binlog日志文件,通过一个统一的index文件来组织。
  • 其他:
    1. 两种模式:
      (1) statement 格式的话是记sql语句。
      (2) row 格式会记录行的内容,记两条,更新前和更新后都有。

    2. 系统给 binlog cache 分配了一片内存,每个线程一个,参数 binlog_cache_size 用于控制单个线程内 binlog cache 所占内存的大小。

    3. write(日志写到缓存页) 和 fsync(数据持久化到磁盘) 的时机,是由参数 sync_binlog 控制的:

      (1) sync_binlog=0 的时候,表示每次提交事务都只 write,不 fsync;

      (2) sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;

      (3) sync_binlog=N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。

      ps: 在出现 IO 瓶颈的场景里,将 sync_binlog 设置成一个比较大的值(100~1000),可以提升性能。但风险是如果主机发生异常重启,会丢失最近 N 个事务的 binlog 日志。

undo log

  • 内容:逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。

  • 作用:保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。

  • 产生条件:事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性。

  • 释放条件:当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。

  • 对应的物理文件:

    MySQL5.6之前,undo表空间位于共享表空间的回滚段中,共享表空间的默认的名称是ibdata,位于数据文件目录中。
    MySQL5.6之后,undo表空间可以配置成独立的文件,但是提前需要在配置文件中配置,完成数据库初始化后生效且不可改变undo log文件的个数
    如果初始化数据库之前没有进行相关配置,那么就无法配置成独立的表空间了。

    关于MySQL5.7之后的独立undo 表空间配置参数如下:

    innodb_undo_directory = /data/undospace/ –undo独立表空间的存放目录

    innodb_undo_logs = 128 –回滚段为128KB

    innodb_undo_tablespaces = 4 –指定有4个undo log文件

  • 其他:undo是在事务开始之前保存的被修改数据的一个版本,产生undo日志的时候,同样会伴随类似于保护事务持久化机制的redolog的产生。

redolog和binlog的不同点:

  • redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  • redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
  • redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

为保证数据库的一致性,必须要保证2份日志一致,使用两阶段提交
例如,一个update语句的执行流程图:\

PS: 假如redolog只是完成了prepare, 而binlog又失败,那么事务本身会回滚,保证事务的一致性。

日志常见问题

Q1:一个SQL语句平时速度都挺快的,偶尔会慢是怎么回事?

原因可能就是数据库在刷脏页(flush)。基于WAL机制,数据库将随机写转换成了顺序写,大大提升了数据库的性能。

InnoDB处理更新时大致流程为:

1
写入 redo log(重做日志)--> 更新到内存,并返回客户端成功 --> 找时机将内存数据刷到硬盘,即刷脏页(flush)

但是也带来了内存脏页的问题(当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”)。脏页会被后台线程自动 flush,也会由于数据页淘汰而触发 flush,而刷脏页的过程由于会占用资源,所以出现偶尔会很慢的情况。

解决:

  1. 正确设置磁盘能力:通过参数innodb_io_capacity设置。建议设置成磁盘的 IOPS。磁盘的 IOPS 可以通过 fio 这个工具来测试。
  2. 关注脏页比例:通过参数innodb_max_dirty_pages_pct设置脏页比例上限,默认值是 75%。脏页比例是通过 Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total 得到的。
  3. 清理接邻脏页:通过参数innodb_flush_neighbors,值为 1 的时候会有上述的“连坐”机制,值为 0 时表示不找邻居,自己刷自己的。
    对于机械硬盘,建议设置为1;对于SSD,建议设置为0( MySQL 8.0 中,innodb_flush_neighbors 参数的默认值是 0 )

Q2:如果 MySQL 现在出现了性能瓶颈,而且瓶颈在 IO 上,可以通过哪些方法来提升性能呢?

  1. 使用组提交。设置 binlog_group_commit_sync_delaybinlog_group_commit_sync_no_delay_count 参数,减少 binlog 的写盘次数。
  2. sync_binlog 设置为大于 1 的值(比较常见是 100~1000)。
  3. innodb_flush_log_at_trx_commit 设置为 2。

事务

四大事务:ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)

  • 原子性:一个事务必须视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行成功其中的一部分操作。
  • 一致性:数据总是从一个一致性的状态转换到另一个一致性的状态。
  • 隔离性:一个事务所做的修改在最终提交以前,对其他事务是不可见的,多个并发事务之间是相互隔离的。关于事务的隔离性,MySQL提供了四种隔离级别。
  • 持久性:一旦事务提交,所做的修改会永久保存到数据库中。即使系统崩溃,修改的数据也不会丢失。

如果不考虑事务的隔离性,会出现三大问题:

  • 脏读(dirty read):指在一个事务处理过程中读取了另一个未提交的事务中的数据。

  • 不可重复读(non-repeatable read):指对于数据库中的某个数据,由于在事务执行过程中,数据被另一个事务修改并提交了,导致一个事务内多次查询却返回了不同的数据值(针对update操作)。

  • 幻读(phantom read):指对于某一个事务执行过程中,由于数据被另一个事务删除(新增)了,导致在这个事务内查询(不)到了数据,但又删除(新增)失败了(针对insert和delete操作)。
    幻读的正确理解:

    事务A 事务B
    开启事务
    开启事务
    查询数据“吴四”,不存在
    插入数据“吴四”
    提交事务
    查询数据“吴四”,不存在
    插入数据“吴四”,不成功

    事务A查询“吴四”,查询不到,插入又不成功,“吴四”这条数据就像幻觉一样出现。这就是所谓的“幻读”。

事务的隔离性的三个问题都是一个事务被另外一个事务影响导致出现读不一致。

四种事务隔离级别:

  • 读未提交(read uncommitted):一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交(read committed):一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读(repeatable read):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
  • 串行化(serializable ):对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。

InnoDB存储引擎默认隔离级别REPEATABLE READ,通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。
在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。

PS:

建议不要使用长事务。长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

MYSQL有两种事务启动模式:

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。
    建议使用 set autocommit=1, 通过显式语句的方式来启动事务。可以使用commit work and chain提交事务并自动启动下一个事务,较少交互次数。

可重复读的核心就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。读提交的逻辑和可重复读的逻辑类似,它们最主要的区别是:

  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;
  • 在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。

InnoDB 的行数据有多个版本,每个数据版本有自己的 row trx_id,每个事务或者语句有自己的一致性视图。普通查询语句是一致性读,一致性读会根据 row trx_id 和一致性视图确定数据版本的可见性。

  • 对于可重复读,查询只承认在事务启动前就已经提交完成的数据;
  • 对于读提交,查询只承认在语句启动前就已经提交完成的数据;
  • 当前读,更新数据都是先读后写的,即总是读取已经提交完成的最新版本。

索引

索引数据结构

索引的出现是为了提高查询效率,常见的索引数据结构有希表、有序数组和搜索树。

其中,哈希表适用于只有等值查询的场景;
有序数组在等值查询和范围查询场景中的性能就都非常优秀,但更新数据时比较麻烦,故有序数组索引只适用于静态存储引擎;
搜索树,大多数的数据库存储却并不使用二叉搜索树,因为对于大数据量可能导致树高过高,读盘时间太慢;为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么就要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。

索引模型

以InnoDBw为例,在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。
InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的,每一个索引在 InnoDB 里面对应一棵 B+ 树。

索引类型分为主键索引和非主键索引:

  • 主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
  • 非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。

索引概念

联合索引

联合索引是多个字段同时建立一个索引,又称为复合索引。

好处:

  1. 减少索引建立的开销。例如建了一个(a,b,c)的复合索引,那么实际等于建了(a),(a,b),(a,b,c)三个索引
  2. 覆盖索引。例如有复合索引(a,b,c),如果有如下的select a,b,c from table where a=1 and b = 1。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机io操作。减少io操作,特别的随机io其实是dba主要的优化策略。
  3. 缩小筛选范围。使用联合索引,可以直接筛选出索引里的数据再进行排序、分页,提高检索效率。

覆盖索引

覆盖索引是select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。覆盖索引可以减少树的搜索次数,显著提升查询性能。

最左前缀原则

所谓最左原则指的就是如果你的 SQL 语句中用到了联合索引中的最左边的索引,那么这条 SQL 语句就可以利用这个联合索引去进行匹配,值得注意的是,当遇到范围查询(>、<、between、like)就会停止匹配。
在创建联合索引时,第一原则是如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。第二考虑的原则就是空间。比如a字段比b字段大,那建议创建一个(a, b) 的联合索引和一个 (b) 的单字段索引。

索引下推

MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
例如,表T有数据((吴一,20, 1),(吴二,10, 2),(吴三,22, 1),(张三, 20, 1))和联合索引(name, age)。
在执行的SQL语句select * from T where name like '吴%' and age=10 and gender=1;,在搜索索引树的时候,只能用 “吴”,找到第一个满足条件的记录D1。

在 MySQL 5.6 之前,只能从 D1 开始一个个回表。即找出全部”吴”的记录,然后到到主键索引上找出数据行,再对比字段值。
在 MySQL 5.6 之后,索引可以在找出”吴”记录的同时,内部判断age=10,对于不满足的记录直接跳过,较少了回表的次数。

索引常见问题

Q1:基于主键索引和普通索引的查询有什么区别?

主键索引查询方式,只需要搜索主键对应字段的B+树;普通索引查询方式,需要先搜索普通索引树,得到主键后再搜索主键索引树(称为回表),也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。

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

这两类索引在查询能力上是没差别的,主要考虑的是对更新性能的影响。建议尽量选择普通索引。

根据加锁的范围,MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类。

全局锁

全局锁的典型使用场景就是做全库逻辑备份(把整库每个表都 select 出来存成文本),用来保证一致性。

MySQL 提供了一个加全局读锁的方法,命令是Flush tables with read lock (FTWRL),适用于 MyISAM 这种不支持事务的引擎。
官方自带的逻辑备份工具是 mysqldump。当 mysqldump 使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于 MVCC 的支持,这个过程中数据是可以正常更新的。适用于 InnoDB 支持事务的引擎。

表级锁

MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。

表锁

表锁的语法是 lock tables … read/write。与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。需要注意,lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。

MDL(metadata lock)

MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的作用是,保证读写的正确性。
在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。

  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。
  • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

PS: 事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。若事务不提交,就会一直占有MDL锁,如果表的查询频繁,且客户端有重试机制的话,整个库的线程池很快就会被占满(重试发起新的session进行请求)。

行锁

行锁就是针对数据表中行记录的锁。MyISAM 引擎就不支持行锁。InnoDB行级锁是通过锁索引记录实现的,如果更新的列没建索引是会锁住整个表的。

两阶段锁协议:在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。
建议:如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。
死锁:当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态。

解决方案:

  1. 通过参数 innodb_lock_wait_timeout 根据实际业务场景来设置超时时间,InnoDB引擎默认值是50s。
  2. 发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑(默认是开启状态)。

锁常见问题

Q1: 为什么不使用 set global readonly=true 的方式让全库进入只读状态呢?

  1. 在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式影响面更大。
  2. 在异常处理机制上有差异。如果执行 FTWRL 命令之后由于客户端发生异常断开,MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。而readonly发生异常,数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。
  3. readonly在 slave 上 如果用户有超级权限的话 readonly 是失效的。

Q2:如何安全地给小表加字段,才能避免事务未提及,MDL锁未释放,客户端不断重试导致的数据库线程池被占满?

  1. 首先要解决长事务,事务不提交,就会一直占着 MDL 锁。在 MySQL 的 information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。如果你要做 DDL 变更的表刚好有长事务在执行,要考虑先暂停 DDL,或者 kill 掉这个长事务。

  2. 若是热点表,即使kill掉事务后,可能很快就又会启动新的事务,不太适合kill的方式解决。
    可在alter表的时候,增加等待时间,如果在等待的时间内拿到了MDL锁,就可以变更,如果拿不到也不要堵塞业务查询。 之后再重复尝试修改Mysql未支持alter等待时间, AliSQL和MariaDb支持,语法:

    1
    2
    ALTER TABLE tbl_name NOWAIT add column ...
    ALTER TABLE tbl_name WAIT N add column ...

Q3:如何解决热点行更新导致的性能问题?

  1. 如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关闭掉。一般不建议采用。
  2. 控制并发度,对应相同行的更新,在进入引擎之前排队。这样在InnoDB内部就不会有大量的死锁检测工作了。
  3. 将热更新的行数据拆分成逻辑上的多行来减少锁冲突,但是业务复杂度可能会大大提高。

Q4:MYSQL为什么有时会选错索引?怎么解决?

优化器选择索引是一个需要各种因素综合评估的事情,比如:是否使用临时表、是否排序、扫描的行数多少、回表的次数等。
但会因为某些原因让优化器选择索引时选错了(不是最优的),算是MYSQL的BUG。
解决:

  • 强制指定使用某个索引,不常用不推荐用
  • 调整SQL语句,使优化器选择的和我们想的一样,不具有通用性
  • 新建更合适的索引或者删除不合适的索引,是一个思路
  • 使用 analyze table 可以解决索引统计信息不准确导致的索引选错的问题

实践

误删数据怎么办?

误操作恢复:

  1. DML误操作语句造成数据不完整或者丢失(delete),可以用 Flashback 工具通过闪回把数据恢复回来。Flashback 恢复数据的原理,是修改 binlog 的内容,拿回原库重放。而能够使用这个方案的前提是,需要确保 binlog_format=rowbinlog_row_image=FULL

  2. DDL语句误操作(truncate和drop),需要使用全量备份,加增量日志的方式。前提是要求线上有定期的全量备份,并且实时备份 binlog。为了加速数据恢复,如果这个临时库上有多个数据库,可以在使用 mysqlbinlog 命令时,加上一个–database 参数,用来指定误删表所在的库;在应用日志的时候,需要跳过误操作的那个语句的 binlog。

    ps: mysqlbinlog 方法恢复数据还是不够快。一种加速的方法是,在用备份恢复出临时实例之后,将这个临时实例设置成线上备库的从库,这样:
    在 start slave 之前,先通过执行change replication filter replicate_do_table = (tbl_name) 命令,就可以让临时库只同步误操作的表。

误操作预防:
预防远比处理的意义来得大。

  1. MySQL 5.6 支持延迟复制的备库,通过 CHANGE MASTER TO MASTER_DELAY = N 命令,可以指定这个备库持续保持跟主库有 N 秒的延迟。
  2. 账号分离。日常也都规定只使用只读账号,必要的时候才使用有更新权限的账号。
  3. 制定操作规范。如在删除数据表之前,对表进行先改名(加固定后缀如_to_be_deleted)观察一段时间后再删除。
  4. 做好sql审计。只要是对线上数据有更改操作的语句(DML和DDL)都需要进行审核。
  5. 做好备份。对于数据量大的用物理备份xtrabackup;数据量较少,用mysqldump或者mysqldumper。

grant之后要跟着flush privileges吗?

grant 语句会同时修改数据表和内存,判断权限的时候使用的是内存数据。因此,规范地使用 grant 和 revoke 语句,是不需要随后加上 flush privileges 语句的。
flush privileges 语句本身会用数据表的数据重建一份内存权限数据,所以在权限数据可能存在不一致的情况下再使用。
而这种不一致往往是由于直接用 DML 语句操作系统权限表导致的,所以我们尽量不要使用这类语句。
权限范围总结:

评论