重命名锁定的表

时间:2016-03-24 14:14:12

标签: mysql mariadb

将表迁移到新模式时,我希望确保使用复制和重命名过程将原子切换到新表。因此,我试图重命名这样一个锁定的表:

CREATE TABLE foo_new (...)

-- copy data to new table, might take very long
INSERT INTO foo_new (id,created_at,modified_at)
  SELECT * FROM foo WHERE id <= 3;

LOCK TABLES foo WRITE, foo_new WRITE;

-- quickly copy the tiny rest over
INSERT INTO foo_new (id,created_at,modified_at)
  SELECT * FROM foo WHERE id > 3;

-- now switch to the new table
RENAME TABLE foo TO foo_old, foo_new TO foo;

UNLOCK TABLES;

不幸的是,这会产生ERROR 1192 (HY000): Can't execute the given command because you have active locked tables or an active transaction

如何以不同方式完成这项工作?

这是mariadb:10.1

4 个答案:

答案 0 :(得分:7)

虽然一般来说Rick使用Percona工具是正确的(请参阅12),但问题的答案实际上是使用JSON.parse(escaped_query_string_from_db)。我认为ALTER TABLE只是一个别名 - 但是it seems like that's not the case

测试似乎表明这个工作正常:

RENAME

答案 1 :(得分:1)

你可以这样做:

CREATE TABLE foo_old (...)
LOCK TABLES foo WRITE; 
INSERT INTO foo_old (id,created_at,modified_at)
  SELECT * FROM foo;
DELETE FROM foo WHERE id <= 3;
UNLOCK TABLES;

正如错误消息所述,在锁定相同表时,您无法使用RENAME TABLE

答案 2 :(得分:0)

不要重新发明轮子......使用Percona&#39; s pt-online-schema-change;它负责细节。

答案 3 :(得分:0)

“在LOCK和UNLOCK STATEMENT之间不应写入或读取任何数据。”

我遇到了同样的问题,并在MySQL文档中找到了原因:

MySQL8.0

As of MySQL 8.0.13, you can rename tables locked with a LOCK TABLES statement, provided that they are locked with a WRITE lock or are the product of renaming WRITE-locked tables from earlier steps in a multiple-table rename operation.

MySQL5.7

To execute RENAME TABLE, there must be no active transactions or tables locked with LOCK TABLES. 

顺便说一句,在MySQL 5.7中,当表被“ LOCK table tbl WRITE”语句锁定时, 由于执行了“ ALTER TABLE tbl_0 RENAME TO tbl_1”,该锁将被释放。 并且在同一会话和新会话中会发生奇怪的行为。

# MySQL 5.7

# session 0
mysql> lock tables tbl_0 WRITE;
Query OK, 0 rows affected (0.02 sec)

mysql> ALTER TABLE tbl_0 RENAME TO tbl_1;
Query OK, 0 rows affected (0.02 sec)

mysql> select * from tbl_1;
ERROR 1100 (HY000): Table 'tbl_1' was not locked with LOCK TABLES

# then start new session 
# session 1
mysql> select * from tbl_1;
...
1 row in set (0.01 sec)

# session 0
mysql> unlock tables;

希望它会有所帮助。