暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySql索引失效行锁变表锁

健身程序员 2020-12-08
892

前言

    众所周知,mysql5后采用InnoDB引擎,而InnoDB引擎默认是行锁,这里不做过多赘述,今天主要讲下索引失效引起的行锁变表锁。

测试表结构

    create table test_lock(
    a int(11),
    b varchar(16)
    )engine=innodb;


    insert into test_lock values(1,'b2');
    insert into test_lock values(3,'3');
    insert into test_lock values(4,'4000');
    insert into test_lock values(5,'5000');
    insert into test_lock values(6,'6000');
    insert into test_lock values(7,'7000');
    insert into test_lock values(8,'8000');
    insert into test_lock values(9,'9000');


    create index idx_a on test_lock(a);
    create index idx_b on test_lock(b);

    表数据

    必备常识

        当字段为varchar类型查询时不加引号('')会导致索引失效,如下:

    如上图可以看出加了引号用到索引idx_b了,而不加引号就没有用到索引,在更新数据时,会导致InnoDB行锁变表锁。


    行锁变表锁

    为了演示容易观看,我开了两个客户端,并且设置不自动提交事务。

    我们知道InnoDB更新时的行锁,在更新不同的行时是不干扰的。请看如下例子:

    左边执行完,在执行右边,更新不同行数据,没有发生阻塞。确定是行锁。

    提交后查询,两个客户端都能查询到更新的数据。

    当我去掉引号做同样的更新更新时,如下:

    此时右边发生阻塞,说明行锁变表锁。

    当我左边提交事务后,右边阻塞消失,执行成功。

    此时两边同时更新成功。

        后面编写sql时一定要注意加引号,否则不仅会导致索引失效还会导致发生阻塞等一系列问题。


    补充:间隙锁

    如上面所说,不同行的更新是不会干扰的。这里也有个特例。

    左边更新数据并没有a=2的行,但是右边发生了阻塞。

    左边提交事务后,右边插入成功。

    两边都提交事务后,查询更新成功。

    什么是间隙锁

        当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加索,对于键值在条件范围内并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加索,这种锁机制就是所谓的间隙锁(Next-Key锁)。

    危害

        因为Query执行过程中通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。

        间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据,在某些场景下这可能会对性能造成很大的危害。

    文章转载自健身程序员,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论