MySQL 在 ALTER TABLE 上挂起
MySQL hangs on ALTER TABLE
我不太大的 table 在 ALTER 命令上挂起。可能是什么?
只有 15 万行,42 个字段,总共 142 兆字节。 InnoDB 存储引擎和服务器版本:5.5.44-MariaDB MariaDB Server。 1 个字段,'slotindex',是主键:bigint(20) 和 BTREE 类型。
命令:
MariaDB [mydb]> ALTER TABLE `runs` CHANGE `p_w_trans_x` `p_w_tran_x` FLOAT NOT NULL;
Stage: 1 of 2 'copy to tmp table' 65.7% of stage done
Stage: 2 of 2 'Enabling keys' 0% of stage done
将在这个阶段2中永远挂起。
那么进程列表如下:
MariaDB [(none)]> show full processlist;
+--------+------+-----------------+-----------+---------+-------+---------------------------------+---------------------------------------------------------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+--------+------+-----------------+-----------+---------+-------+---------------------------------+---------------------------------------------------------------------+----------+
| 274226 | root | localhost:45423 | edc_proxy | Sleep | 16043 | | NULL | 0.000 |
| 274319 | root | localhost | myDB | Query | 99 | Waiting for table metadata lock | ALTER TABLE `runs` CHANGE `p_w_trans_x` `p_w_tran_x` FLOAT NOT NULL | 0.000 |
| 274416 | root | localhost | NULL | Query | 0 | NULL | show full processlist | 0.000 |
+--------+------+-----------------+-----------+---------+-------+---------------------------------+---------------------------------------------------------------------+----------+
这个 answer 建议检查 information_schema tables,那里不多:
MariaDB [INFORMATION_SCHEMA]> SELECT * FROM INNODB_LOCK_WAITS;
Empty set (0.00 sec)
MariaDB [INFORMATION_SCHEMA]> SELECT * FROM INNODB_LOCKS ;
Empty set (0.00 sec)
MariaDB [INFORMATION_SCHEMA]> SELECT * FROM INNODB_TRX;
+----------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+
| trx_id | trx_state | trx_started | trx_requested_lock_id | trx_wait_started | trx_weight | trx_mysql_thread_id | trx_query | trx_operation_state | trx_tables_in_use | trx_tables_locked | trx_lock_structs | trx_lock_memory_bytes | trx_rows_locked | trx_rows_modified | trx_concurrency_tickets | trx_isolation_level | trx_unique_checks | trx_foreign_key_checks | trx_last_foreign_key_error | trx_adaptive_hash_latched | trx_adaptive_hash_timeout |
+----------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+
| 83A8B36E | RUNNING | 2016-12-08 11:13:02 | NULL | NULL | 0 | 274226 | NULL | NULL | 0 | 0 | 0 | 376 | 0 | 0 | 0 | REPEATABLE READ | 1 | 1 | NULL | 0 | 10000 |
+----------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+
1 row in set (0.00 sec)
以及来自 show engine innodb status;
的交易部分:
------------
TRANSACTIONS
------------
Trx id counter 83A8F071
Purge done for trx's n:o < 83A8CA86 undo n:o < 0
History list length 1490
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 274543, OS thread handle 0x7fbb863e6700, query id 85356480 localhost root
show engine innodb status
---TRANSACTION 83A8EB07, not started
mysql tables in use 1, locked 2
MySQL thread id 274542, OS thread handle 0x7fbb843f6700, query id 85354935 localhost root Waiting for table metadata lock
ALTER TABLE `runs` CHANGE `p_w_trans_x` `p_w_tran_x` FLOAT NOT NULL
---TRANSACTION 83A8B36E, ACTIVE 24627 sec
MySQL thread id 274226, OS thread handle 0x7fbb845f5700, query id 85337236 localhost 127.0.0.1 root
Trx read view will not see trx with id >= 83A8B36F, sees < 83A8B36D
----------------------------
END OF INNODB MONITOR OUTPUT
============================
感谢任何进一步调查、规避问题和解决问题的建议!
元数据锁是一种隐式(从用户的角度来看)锁,可以防止 DDL 针对 table,因为其他东西需要 table 以保持其当前形式。在这种情况下,这是一笔交易 运行.
任务 1:如果您终止线程 274226 上的连接,您的更改将会成功。
mysql> KILL 274226;
这里的问题,如 information_schema.innodb_trx 所示,是这个线程已经离开一个事务 运行 几个小时了,我们可以推断这个 table 已经被那个引用了交易。在没有事务仍然具有 MVCC 视图或任何涉及 table 的锁之前,无法更改 table。此事务持有一个视图,我们可以再次推断 可能 影响此 table,如最后一行所示:
--TRANSACTION 83A8B36E, ACTIVE 24627 sec
MySQL thread id 274226, OS thread handle 0x7fbb845f5700, query id 85337236 localhost 127.0.0.1 root
Trx read view will not see trx with id >= 83A8B36F, sees < 83A8B36D
请注意,Sleep
不是真正的命令,在此上下文中,它只是任何空闲连接的占位符状态。所有连接都在做某事,在这种情况下 "something" 正在休眠——换句话说,空闲并等待另一个查询。但是空闲连接仍然是连接,如果您的代码(或查询浏览器工具)离开事务 运行,它只会保持 运行.
任务 2:找到留下该交易的漏洞或错误 运行。在实时应用程序中,保留事务 运行 可能会造成更大的混乱。
我遇到了与 table 锁非常相似的问题,但它最终变成了 MySQL Workbench。 MySQL Workbench 中的任何 RENAME TABLE
或 ALTER TABLE
命令都只会占用一个元锁。我登录到服务器并能够毫无问题地执行这些类型的查询。 Workbench 的当前版本是 8.0.22
。
我筛选了所有这些查询,当它们没有显示任何问题时我完全被难住了:
SHOW OPEN TABLES;
SHOW ENGINE inndodb STATUS;
SELECT * FROM INNODB_LOCK_WAITS;
SELECT * FROM INNODB_LOCKS;
SELECT * FROM INNODB_TRX;
SHOW FULL PROCESSLIST;
我不太大的 table 在 ALTER 命令上挂起。可能是什么?
只有 15 万行,42 个字段,总共 142 兆字节。 InnoDB 存储引擎和服务器版本:5.5.44-MariaDB MariaDB Server。 1 个字段,'slotindex',是主键:bigint(20) 和 BTREE 类型。
命令:
MariaDB [mydb]> ALTER TABLE `runs` CHANGE `p_w_trans_x` `p_w_tran_x` FLOAT NOT NULL;
Stage: 1 of 2 'copy to tmp table' 65.7% of stage done
Stage: 2 of 2 'Enabling keys' 0% of stage done
将在这个阶段2中永远挂起。
那么进程列表如下:
MariaDB [(none)]> show full processlist;
+--------+------+-----------------+-----------+---------+-------+---------------------------------+---------------------------------------------------------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+--------+------+-----------------+-----------+---------+-------+---------------------------------+---------------------------------------------------------------------+----------+
| 274226 | root | localhost:45423 | edc_proxy | Sleep | 16043 | | NULL | 0.000 |
| 274319 | root | localhost | myDB | Query | 99 | Waiting for table metadata lock | ALTER TABLE `runs` CHANGE `p_w_trans_x` `p_w_tran_x` FLOAT NOT NULL | 0.000 |
| 274416 | root | localhost | NULL | Query | 0 | NULL | show full processlist | 0.000 |
+--------+------+-----------------+-----------+---------+-------+---------------------------------+---------------------------------------------------------------------+----------+
这个 answer 建议检查 information_schema tables,那里不多:
MariaDB [INFORMATION_SCHEMA]> SELECT * FROM INNODB_LOCK_WAITS;
Empty set (0.00 sec)
MariaDB [INFORMATION_SCHEMA]> SELECT * FROM INNODB_LOCKS ;
Empty set (0.00 sec)
MariaDB [INFORMATION_SCHEMA]> SELECT * FROM INNODB_TRX;
+----------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+
| trx_id | trx_state | trx_started | trx_requested_lock_id | trx_wait_started | trx_weight | trx_mysql_thread_id | trx_query | trx_operation_state | trx_tables_in_use | trx_tables_locked | trx_lock_structs | trx_lock_memory_bytes | trx_rows_locked | trx_rows_modified | trx_concurrency_tickets | trx_isolation_level | trx_unique_checks | trx_foreign_key_checks | trx_last_foreign_key_error | trx_adaptive_hash_latched | trx_adaptive_hash_timeout |
+----------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+
| 83A8B36E | RUNNING | 2016-12-08 11:13:02 | NULL | NULL | 0 | 274226 | NULL | NULL | 0 | 0 | 0 | 376 | 0 | 0 | 0 | REPEATABLE READ | 1 | 1 | NULL | 0 | 10000 |
+----------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+
1 row in set (0.00 sec)
以及来自 show engine innodb status;
的交易部分:
------------
TRANSACTIONS
------------
Trx id counter 83A8F071
Purge done for trx's n:o < 83A8CA86 undo n:o < 0
History list length 1490
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 274543, OS thread handle 0x7fbb863e6700, query id 85356480 localhost root
show engine innodb status
---TRANSACTION 83A8EB07, not started
mysql tables in use 1, locked 2
MySQL thread id 274542, OS thread handle 0x7fbb843f6700, query id 85354935 localhost root Waiting for table metadata lock
ALTER TABLE `runs` CHANGE `p_w_trans_x` `p_w_tran_x` FLOAT NOT NULL
---TRANSACTION 83A8B36E, ACTIVE 24627 sec
MySQL thread id 274226, OS thread handle 0x7fbb845f5700, query id 85337236 localhost 127.0.0.1 root
Trx read view will not see trx with id >= 83A8B36F, sees < 83A8B36D
----------------------------
END OF INNODB MONITOR OUTPUT
============================
感谢任何进一步调查、规避问题和解决问题的建议!
元数据锁是一种隐式(从用户的角度来看)锁,可以防止 DDL 针对 table,因为其他东西需要 table 以保持其当前形式。在这种情况下,这是一笔交易 运行.
任务 1:如果您终止线程 274226 上的连接,您的更改将会成功。
mysql> KILL 274226;
这里的问题,如 information_schema.innodb_trx 所示,是这个线程已经离开一个事务 运行 几个小时了,我们可以推断这个 table 已经被那个引用了交易。在没有事务仍然具有 MVCC 视图或任何涉及 table 的锁之前,无法更改 table。此事务持有一个视图,我们可以再次推断 可能 影响此 table,如最后一行所示:
--TRANSACTION 83A8B36E, ACTIVE 24627 sec
MySQL thread id 274226, OS thread handle 0x7fbb845f5700, query id 85337236 localhost 127.0.0.1 root
Trx read view will not see trx with id >= 83A8B36F, sees < 83A8B36D
请注意,Sleep
不是真正的命令,在此上下文中,它只是任何空闲连接的占位符状态。所有连接都在做某事,在这种情况下 "something" 正在休眠——换句话说,空闲并等待另一个查询。但是空闲连接仍然是连接,如果您的代码(或查询浏览器工具)离开事务 运行,它只会保持 运行.
任务 2:找到留下该交易的漏洞或错误 运行。在实时应用程序中,保留事务 运行 可能会造成更大的混乱。
我遇到了与 table 锁非常相似的问题,但它最终变成了 MySQL Workbench。 MySQL Workbench 中的任何 RENAME TABLE
或 ALTER TABLE
命令都只会占用一个元锁。我登录到服务器并能够毫无问题地执行这些类型的查询。 Workbench 的当前版本是 8.0.22
。
我筛选了所有这些查询,当它们没有显示任何问题时我完全被难住了:
SHOW OPEN TABLES;
SHOW ENGINE inndodb STATUS;
SELECT * FROM INNODB_LOCK_WAITS;
SELECT * FROM INNODB_LOCKS;
SELECT * FROM INNODB_TRX;
SHOW FULL PROCESSLIST;