MariaDB上的TRUNCATE表刚刚开始挂起

时间:2019-06-16 15:47:22

标签: mysql mariadb

我在多个位置运行10.1.26-MariaDB-0+deb9u1 Debian 9.1

今天刚接到电话,说某些脚本不再在其中一个位置上运行。我已经诊断出,每当脚本尝试执行TRUNCATE <table name>时,脚本都会挂起。

我也已经在CLI和Workbench中尝试过,但结果相同。我也尝试过TRUNCATE TABLE <table name>,但结果相同。

我不知道A)为什么这突然停止了工作。和B)这个位置与其他三个位置有什么不同?

1 个答案:

答案 0 :(得分:2)

我希望您看到这样的内容:

mysql> show processlist;
+----+-----------------+-----------+------+---------+------+---------------------------------+------------------------+
| Id | User            | Host      | db   | Command | Time | State                           | Info                   |
+----+-----------------+-----------+------+---------+------+---------------------------------+------------------------+
|  8 | msandbox        | localhost | test | Query   |  435 | Waiting for table metadata lock | truncate table mytable |

在MySQL的测试实例中尝试该实验(例如在本地开发环境中):打开两个shell窗口并运行mysql客户端。创建测试表。

mysql> create table test.mytable ( answer int );
mysql> insert into test.mytable set answer = 42;

现在开始事务并查询表,但尚未提交事务。

mysql> begin;

mysql> select * from test.mytable;
+--------+
| answer |
+--------+
|     42 |
+--------+

在第二个窗口中,尝试截断该表。

mysql> truncate table mytable;
<hangs>

它正在等待的是元数据锁定。。它将等待与lock_wait_timeout配置选项相等的秒数。

现在返回第一个窗口并提交。

mysql> commit;

现在在第二个窗口中看到,TRUNCATE TABLE不再等待,它终于完成了工作,将表截断了。

任何DDL语句(如ALTER TABLE,TRUNCATE TABLE,DROP TABLE)都需要获取表上的独占元数据锁。但是,任何已在读取或写入该表的事务都拥有共享的元数据锁。这意味着许多并发会话可以完成其工作,例如SELECT / UPDATE / INSERT / DELETE,而不会互相阻塞(因为它们的锁是共享的)。但是DDL语句需要排他的元数据锁,这意味着不能存在共享或排他的其他元数据锁。

因此,我猜想有一些事务在未提交的情况下对您的表进行了一些读取或写入操作。查询本身可能需要很长时间才能运行,或者查询已经完成但事务尚未完成。

您必须弄清楚在哪里有一笔未完成的交易。如果您使用的是MySQL 5.7或更高版本,则可以在其中一个截断表语句正在等待时读取sys.schema_lock_waits表。

select * from sys.schema_table_lock_waits\G
*************************** 1. row ***************************
               object_schema: test
                 object_name: mytable
           waiting_thread_id: 47
                 waiting_pid: 8
             waiting_account: msandbox@localhost
           waiting_lock_type: EXCLUSIVE
       waiting_lock_duration: TRANSACTION
               waiting_query: truncate table mytable
          waiting_query_secs: 625
 waiting_query_rows_affected: 0
 waiting_query_rows_examined: 0
          blocking_thread_id: 48
                blocking_pid: 9
            blocking_account: msandbox@localhost
          blocking_lock_type: SHARED_READ
      blocking_lock_duration: TRANSACTION
     sql_kill_blocking_query: KILL QUERY 9
sql_kill_blocking_connection: KILL 9

这告诉我们哪个会话被阻止,等待元数据锁定。 waiting_pid(在上例中为8)对应于被阻止会话的进程列表中的Id

blocking_pid(在上例中为9)对应于当前持有锁并正在阻止截断表的会话的进程列表中的Id

它甚至告诉您确切如何杀死持有锁的会话:

mysql> KILL 9;

一旦会话被杀死,它必须释放其锁,并且截断表最终完成。

mysql> truncate table mytable;
Query OK, 0 rows affected (13 min 34.50 sec)

不幸的是,您正在使用MariaDB 10.1。这不支持需要报告这些锁的sys模式或Performance_schema.metadata_locks表。 MariaDB是MySQL 5.5的分支,MySQL已有将近十年的历史了,那时他们还没有metadata_locks表。

我不使用MariaDB,但我在Google上搜索后发现,它们具有用于查询元数据锁的专有实现:https://mariadb.com/kb/en/library/metadata_lock_info/我没有使用过,因此请留给您阅读文档。