update 锁表经验分享(2)

2019-05-14  本文已影响0人  燃英

很多情况下慢SQL会导致数据库锁表甚至服务器宕机。

如果一个线程开启了一个事务,然后执行了一条慢SQL,这就意味着在它执行结束前,这个事务所占的资源(行记录或者表)就会被锁定,所以优化SQL、合理使用SQL是避免数据库锁表和系统崩溃的重要保障。

看SQL:

BEGIN;

UPDATE tapp_user
SET `status` ='active', modified = NOW()
WHERE
    order_id = (
        SELECT
            id
        FROM
            tapp_user_order
        WHERE
            order_no = 'f28c5e82683d4ccf8c7104d83b949276'
    )
AND `status` = 'inactive'
;

COMMIT;

这个 sql 是根据订单号更新用户的一个状态,但是订单号在订单表,状态在用户表,此时根据订单号查询到对应的用户,再去更新用户状态。

首先,这条SQL语句是表级锁,也就是意味着整个 tapp_user 表都会被锁定,任何一条更新 tapp_user 表的记录都要等待。

测试:

1、我们打开Navicat,新建一个查询,运行 begin;
2、然后再运行SQL ,注意不 commit;
3、再新建一个查询,运行begin;
4、接着在这个新的查询页里面运行一条简单的SQL 比如: update tapp_user set status = 'inactive' where id = 65;
此时我们就可以看到两个SQL都是一直在执行的状态,没有出现执行结果。直到报错:

lock.jpg

有些朋友就会问了,自己经常这么写,为什么没有问题?
答: 数据量还不够,并发还不够多。
如果订单表里面有上千万的数据,并发量达到1000+ ,稍微有什么地方没弄好,就会出现系统卡顿,然后宕机。

日志里一般会有:

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

所以我们使用update语句的时候,要尽量避免表级锁,能用主键查询的尽量用主键,比如根据订单更新,就可以先根据订单号查询订单表,再根据订单表找到用户表,这样效率反而会增加。

上一篇下一篇

猜你喜欢

热点阅读