🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
索引可以让查询锁定更少的行.如果你的查询从不访问哪些不需要的行,那么就会锁定更少的行,从两方面来看这对性能都有好处. Innodb只有在访问行的时候才会对其加锁,而索引能够减少Innodb访问的行数,从而减少锁的数量.但这只有当Innodb在存储引擎层能够过滤掉索引不需要的行的时候才有效果, 如果索引无法过滤无效的行,那么在Innodb检索到数据并返回给服务层以后,mysql服务器才能应用到where子句.这时候已经无法避免锁定行了,innodb已经锁定这些行了,到适当的时候才会释放, 在mysql5.1以及更新版本的时候,innodb可以在服务器端过滤掉后就释放锁,但是在早期的mysql版本中,Innodb只有在事务提交后才能释放锁 看下面的例子 ~~~ set autocommit = 0 ; begin; select actor_id from sakila.actor where actor_id < 5 and actor_id <> 1 for update; ~~~ ![](https://box.kancloud.cn/b13cee526a474de61df9849bb23cd534_675x310.png) 底层的存储引擎的操作是"从索引头开始获取满足条件actor_id < 5"的记录,服务器并没有告诉Innodb可以过滤第一行的where条件,注意到explain的extra出现了Using where,这表示mysql服务器将存储引擎返回行以后再应用where过滤条件 下面的第二个查询就能证明第一行确实被锁定,尽管第一个查询的结果中并没有这个第一行,保持第一个连接打开,然后开启第二个连接并执行如下的查询 ![](https://box.kancloud.cn/deef840b4a7abaf27a1bc3ee710ea867_586x69.png) 这个查询将会挂起,直到第一个事务释放第1行的锁,这个行为对于基于语句的复制的正常运行来说是必要的.(尽管在理论上使用基于行的日志模式,在某些是事务隔离级别下,服务器不再需要锁定行,但是实际上经常发现无法实现这种预期的行为.知道mysql5.6.3版本,在read-commit隔离级别和基于行的日志模式下,这个例子还是会导致锁) 就像这个例子显示的,即使使用了索引,Innodb也可能锁住一些不需要的数据.如果不能使用索引查找和锁定行的话问题可能会很糟糕,mysql会做全表扫描并锁住所有的行,而不管是不是需要的 关于Innodb,索引和锁有一些很少有人知道的细节,Innodb在二级索引上使用共享(读)锁,但访问主键索引需要排他(写)锁,这消除了使用索引覆盖的可能性,并且使得select for update 比 lock in share mode或非锁定查询要慢很多