《高性能MySQL》笔记-索引和锁

索引可以让查询锁定更少的行。如果你的查询从不访问那些不需要的行,那么就会锁定更少的行,从两个方面来看这对性能都有好处。首先,虽然InnoDB的行锁效率很高,内存使用也很少,但是锁定行的时候仍然会带来额外开销;其次锁定超过需要的行会增加锁争用并减少并发性。
InnoDB只有在访问行的时候才会对其加锁,而索引能够减少InnoDB访问的行数,从而减少锁的数量。但这只有当InnoDB在存储引擎层能够过滤掉所有不需要的行时才有效。如果索引无法过滤掉无效的行,那么在InnoDB检索到数据并返回给服务器层以后,MySQL服务器才能应用WHERE子句。这时已经无法避免锁定行了:InnoDB已经锁住了这些行,到适当的时候才释放。在MySQL5.1和更新的版本中,InnoDB可以在服务器端过滤掉行后就释放锁,但是在早期的MySQL版本中,InnoDB只有在事务提交后才能释放锁。
通过下面的例子很好地解释了这些情况:
《高性能MySQL》笔记-索引和锁_第1张图片
《高性能MySQL》笔记-索引和锁_第2张图片
这个查询仅仅会返回2~4之间的行,但是实际上获取了1~4之间的行的排他锁。InnoDB会锁住第1行,这是因为MySQL为该查询选择的执行计划是索引范围扫描:
《高性能MySQL》笔记-索引和锁_第3张图片
换句话说,底层存储引擎的操作是“从索引的开头开始获取满足条件actor_id < 5的记录“,服务器并没有告诉InnoDB可以过滤第1行的WHERE条件。注意到EXPLAIN的Extra列出现了”Using where“,这表示MySQL服务器将存储引擎返回行以后再应用WHERE过滤条件。
下面的第2个查询就能证明第1行确实已经被锁定了,尽管第1个查询的结果中并没有这个第1行。保持第1个连接打开,然后开启第2个连接并执行如下查询:
图4
这个查询将会挂起,直到第1个事务释放第1行的锁。这个行为对于基于语句的复制的正常运行来说是必要的。
就像这个例子显示的,即使使用了索引,InnoDB也可能锁定一些不需要的数据。如果不能使用索引查找和锁定行的话问题可能会更糟糕,MySQL会做全表扫描并锁住所有的行,而不管是不是需要。
关于InnoDB、索引和锁有一些很少有人知道的细节:InnoDB在二级索引上使用共享(读)锁,但访问主键索引需要排他(写)锁。这消除了使用覆盖索引的可能性,并且使得SELECT FOR UPDATE比LOCK IN SHARE MODE或非锁定查询要慢得多。

你可能感兴趣的:(区块链)