存储过程挂了

Stored procedure hanging

存储过程时常挂起。有什么建议吗?

BEGIN
DECLARE bookId int;

SELECT IFNULL(id,0) INTO bookId FROM products
    WHERE 
        isbn=p_isbn
    and stoc>0 
    and status='vizibil' 
    and pret_ron=(SELECT MAX(pret_ron) FROM products
    WHERE isbn=p_isbn
                  and stoc>0 
                  and status='vizibil')
    ORDER BY stoc DESC

LIMIT 0,1;

IF bookId>0 THEN
UPDATE products SET afisat='nu' WHERE isbn=p_isbn;
UPDATE products SET afisat='da' WHERE id=bookId;
SELECT bookId INTO obookId;
ELSE

SELECT id INTO bookId FROM products
    WHERE 
        isbn=p_isbn 
    and stoc=0 
    and status='vizibil' 
    and pret_ron=(SELECT MAX(pret_ron) FROM products
                    WHERE isbn=p_isbn 
                      and stoc=0 
                      and status='vizibil')
LIMIT 0,1;
UPDATE products SET afisat='nu' WHERE isbn=p_isbn;
UPDATE products SET afisat='da' WHERE id=bookId;
SELECT bookId INTO obookId;
END IF;

END

当它挂起时,它会在: | 23970842 |用户名 | sqlhost:54264 |数据库 |查询 | 65 |发送数据 | SELECT IFNULL(id,0) INTO bookId FROM products 在哪里 isbn= NAME_CONST('p_isbn',_utf8'973-679-50 | 0.000 |

| 1133136 |用户名 | sqlhost:52466 |数据库_emindb |查询 | 18694 |发送数据 | SELECT IFNULL(id,0) INTO bookId FROM products 在哪里 isbn= NAME_CONST('p_isbn',_utf8'606-92266- | 0.000 |

首先,我想提一下 Percona toolkit,它非常适合调试死锁和挂起的事务。其次,我猜想在挂起时,有多个线程在执行同一个过程。我们需要知道的是,挂起时正在获取哪些锁。 MySQL 命令 SHOW INNODB STATUS 为您提供了详细信息。在下'hang'、运行这个命令。

我差点忘了提到innotop这个工具,它很相似,但更好:https://github.com/innotop/innotop

接下来假设你是InnoDB引擎。由于范围锁定,在这种情况下,REPEATABLE READ 的默认事务隔离级别可能太高,您可以考虑对过程的主体尝试 READ COMMITTED(在开始时设置为 READ COMMITTED,并在结束时返回到 REPEATABLE READ)。

最后,也许最重要的是,请注意您的过程使用可能相同的 p_isbn 值对相同的 table 执行 SELECT 和 UPDATE(以混合顺序)。想象一下,如果这个过程 运行s 并发——这是一个完美的死锁设置。