Open git-zjx opened 5 years ago
Online DDL的过程是这样的: ①拿MDL写锁 ②降级成MDL读锁 ③真正做DDL ④升级成MDL写锁 ⑤释放MDL锁; ①、②、④、⑤如果没有锁冲突,执行时间非常短。 第③步占用了 DDL 绝大部分时间,这期间这个表可以正常读写数据,是因此称为“online ”
最早的 DDL 内部实现就是这么做的,不过加锁时间也不短。 “先基于原表创建一个临时表,完成字段更新修改;” 这个过程,要包含“把原表的数据导入临时表”,导入的过程还是对原表加 MDL 锁的。
读锁之间兼容,读写、写写之间需要互相等待
需要切表名
在DDL执行过程中读数据,看到的是修改之前的的表结构
改元数据是在第四步和第五步之间做的,这时候确实持有写锁
为了并发
DML一般指的是增删改,不过若果select ... lock in share mode; select ... for update也会有行锁
是的,有保证主键算进去,还是有序的
全局锁
对整个数据库实例加锁,MySQL 提供一个加全局读锁的命令:Flush tables with read lock(FTWRL),命令执行后,数据更新语句(增删改)、数据定义语句(建表和修改表结构等)和更新类事务都会被阻塞,经常用于数据库备份场景
备份也可以使用 mysqldump 官方自带的逻辑备份工具,参数 -single-transaction 会在导数据之前启动一个事务,确保拿到一致性视图,而由于 MVCC 的支持,这个过程中是可以正常更新的
参数 -single-transaction 需要数据库引擎支持事务,如果不支持就只能使用 FTWRL 方案
为什么不使用 set global readonly = true 方式?
表级锁
MySQL 的表级锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)
lock tables … read/write
语句用于加表锁,使用unlock tables
可以释放锁,客户端断开连接时也会释放锁 需要注意,lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象 举个例子, 如果在某个线程 A 中执行lock tables t1 read, t2 write;
这个语句,则其他线程写 t1、读写 t2 的语句都会被阻塞。同时,线程 A 在执行unlock tables
之前,也只能执行读 t1、读写 t2 的操作。连写 t1 都不允许,自然也不能访问其他表。在 MySQL 5.5 版本中引入了 MDL,MDL 不需要显式调用,在访问一个表时自动调用,主要保证读写的正确性,防止DDL和DML并发的冲突
当表做增删改查操作时,加MDL读锁;当对表结构变更的时候,加MDL写锁
小表加字段为什么会导致整个库崩溃? Session A 会给表 t 加 MDL 读锁,Session B 需要的也是读锁,可以执行 Session C 需要 MDL 写锁,但 Session A 的 MDL 读锁还未释放,需要等待 Session D 需要 MDL 读锁,但是因为 MySQL 内部维护了一个队列决定执行顺序,Session C 阻塞了 Session D 这里可以知道事务中的 MDL 锁会等到整个事务结束后再释放
如何安全的给小表加字段?