多个单独索引是可能被同时使用到的

MySQL5.0之前,单表一次查询只能使用一个索引,无法同时使用多个索引分别进行条件扫描。但是从5.1开始,引入了 index merge 优化技术,对同一个表可以使用多个索引分别进行条件扫描。相关文档:http://dev.mysql.com/doc/refman/5.6/en/index-merge-optimization.html

index(a) index(b)

select * from table where a=1 and b=1 可能会用到索引 a 和 b(index_merge),也可能只用到 a 或者 b

mysql 会选择它觉得快的索引策略,但是 index_merge 不一定能比单索引查询快,这个要根据表里的数据具体分析。

如果没有单独按照 b 查询的场景,这里可以设置为联合索引 index(a, b),查询条件为 a=1 and b=2 时会比上述索引快一些

事务隔离级别

  • 读未提交(Read Uncommitted)
  • 读提交(Read Committed)
  • 可重复读(Repeated Read)
  • 串行化(Serializable)

默认是:可重复读(Repeated Read)

在事务隔离级别为「可重复读」的情况下,会出现「幻读」,这是网上以及各种面试经常看到的问题。

但是「幻读」如何定义,哪些现象被称为「幻读」,却很少有明确的说法。

网上能看到最多的关于幻读的描述是:一个事务相同的 sql 语句读取 2 次,得到的记录条数不一致(由于其他事务在第二次读取之前插入了符合查询条件的数据)。但是 mysql 中隔离级别设置为「可重复读」时,并不存在这个现象,实验环境为10.1.22-MariaDB,大家可以自己实验下。

关于「幻读」的定义还有另一个说法,我们模拟一个业务中比较常见的场景来说明。例如:

给用户给帖子点赞,用 uid 表示用户 id,tid 表示帖子 id,uid + tid 设置为唯一索引。
假如说这时候用户 1 要为帖子 2 点赞,代码做的事情就是:查询用户 1 对帖子 2 有没有点赞记录,如果有就什么都不做,没有则新增一条记录。假如这个操作并发了,A 事务查询点赞记录时没有查到,同时 B 事务查询点赞记录也没有查到,之后 A 事务插入了点赞数据,并且提交事务,然后 B 事务再插入这条数据的时候就会报唯一键冲突,引发异常。这个场景下 B 事务遇到的情况就属于「幻读」

因为前一个说法在 mysql 默认的隔离级别下不存在,据说是“由于 InnoDB 引擎的「可重复读」级别还使用了 MVCC,避免了这个问题”,所以我个人理解后一种才算是「幻读」

关于 mvcc 这里涉及数据库的「并发控制」,可以参考浅谈数据库并发控制 - 锁和 MVCC

这里我还想喷一下部分公司的面试官,上来就问如果出现了「幻读」怎么解决,而不提具体场景,事实上可能大家理解的「幻读」就不是一回事,并且「幻读」是一个抽象概念,不如直接说场景,不知道幻读的概念,不见得不能解决问题

网上关于幻读的解释

  1. 第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。来源

mysql autocommit

表示除非显式地开始一个事务,否则每个查询都被当做一个单独的事务自动执行

关于行锁

InnoDB 通过索引来实现行锁,而不是通过锁住记录。因此,当操作的两条不同记录拥有相同的索引时,也可能会因为行锁而发生等待。

参考文献:

标签: mysql

添加新评论