Innodb中的行级锁

  • Record Lock: 只对记录本身加锁
  • Gap Lock: 锁住记录前的间隙, 防止别的事务向该间隙插入记录
  • Next-Key Lock: 相当于Record Lock和Gap Lock的结合体
  • Insert Intension Lock: 插入意向锁, 它是在当前记录插入时碰到其它事务加的Gap锁后生成的, 没什么用
  • 隐式锁: 依靠记录的trx_id属性保护不被别的事务改动该记录

    什么是 意向锁

    意向锁也分为 意向共享锁(IS锁) 和 意向独占锁(IX锁), 它们都是表级锁
    意向锁是仅仅是为了加表级锁而引入的, 可以快速判断表中是否有被加锁的记录, 而避免用遍历的方式
    原理: 当对记录行上S锁或X锁时, 要先在表级别加一个IS锁或IX锁, 这样只用看一下表是否上了IS锁或IX锁, 若没上说明没有记录被加锁, 才能上表级锁
    注: Innodb才有意向锁

    SQL语句加锁分析

  • 普通的select语句

    • read uncommitted: 不加锁, 直接读取记录的最新版本
    • read committed: 不加锁, 在每次执行普通select语句时, 生成一个ReadView(一致性视图), 读取版本链记录
    • repeatable read: 不加锁, 在第一次执行普通select语句时, 生成一个ReadView
    • serializable:
      • 当禁用自动提交, 执行普通select语句会上S锁, 即语句被转换为select … lock in share mode
      • 当启用自动提交, 不加锁, 生成一个ReadView
  • 特殊的select语句-锁定读
    • select … lock in share mode
      • read uncommitted, read committed: 加S型record锁, 遍历过的不符合条件的会释放锁
      • repeatable read, serializable: 加S型next_key锁, 遍历过的不符合条件的也不释放锁
    • select … for update
      • read uncommitted, read committed: 加X型record锁, 遍历过的不符合条件的会释放锁
      • repeatable read, serializable: 加X型next_key锁, 遍历过的不符合条件的也不释放锁
  • update, delete, insert
    • read uncommitted, read committed: 加X型record锁, 遍历过的不符合条件的会释放锁
    • repeatable read, serializable: 加X型next_key锁, 遍历过的不符合条件的也不释放锁

      如何使用explain分析SQL

change buffer 和 redo log在提升性能上的差别

change buffer 避免了 随机读磁盘的IO消耗
redo log 避免了 随机写磁盘的IO消耗

内存和日志文件什么时候刷到磁盘

掌柜记账的账本是磁盘数据,记账用的粉板是日志文件(redo log),掌柜的记忆就是内存(redo log buffer)

  • redo log写满了, 把cp往前推到cp’, 把这之间的内容flush到磁盘数据页中. 这期间数据库是只读的
  • 系统内存不足, 要把redo log buffer中的内容flush到磁盘数据页中
  • 系统空闲时, 把redo log的内容flush到磁盘数据页中
  • MySQL正常关闭时, 把内存中的脏页flush到磁盘数据页中

MySQL异常崩溃时内存中的脏页没刷盘怎么办?

通过binlog恢复?

事务隔离级别 与 上锁有什么关系?

除了serializable隔离级别下的select语句会上S锁, 其它普通的select语句不上任何锁
- 在 读未提交 隔离级别下, 每次select都不会上锁, 读取最新的记录
- 在 读提交(RC) 隔离级别下, 每次select都不会上锁, 读取数据时都生成一个ReadView(一致性视图), 里面有一个列表m_ids记录了当前未提交的事务id, 读取数据时会顺着记录的版本链向下搜索, 直到找到满足 trx_id < m_ids中最小事务id 的第一条记录
- 在 可重复读(RR) 隔离级别下, 每次select都不会上锁, 只在第一次select读取数据时生成一个ReadView, 所以不管事务期间是否有其它事务提交, 都不会影响之后查询的结果
- 在 串行化 隔离级别下, 每次select都会上S锁, 读取最新的记录, 当最新的记录被其它事务上X锁, 会阻塞当前语句, 直到相应的事务提交

MySQL 主从同步机制

主库A 和 从库B 之间维持了一条TCP长连接,从库B的线程 会先发起同步请求,指明主库的IP,端口,用户名,密码,以及请求的binlog文件名和日志偏移量,
主库A收到请求后校验身份,再把指定的binlog内容发给从库B,从库B收到后,先写到本地的relay_log(中转日志),
从库B的另一条线程sql_thread负责读取中转日志里的命令并执行,这就实现了主从同步

事务什么时候会被分配一个trx_id?

在事务执行过程中,只有在第一次修改记录时才会分配事务id
比如使用insert,update,delete语句,或者start transaction with consistent snapshot

为什么innodb用count(*)计算表行数这么慢?

由于MVCC的存在,每一行记录都要判断自己是否对这个事务可见,所以只好一行行读出依次判断