重命名锁定的 table

renaming a locked table

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

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.

你可以这样做:

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;

如错误消息所述,您不能在锁定相同 table 的情况下使用 RENAME TABLE

不要重新发明轮子...使用 Percona pt-online-schema-change;它会处理细节。

虽然一般来说 Rick 使用 Percona 工具是正确的(参见 1 and 2), the answer to the question really is to use ALTER TABLE. I thought RENAME was just an alias - but it seems like that's not the case

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

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
ALTER TABLE foo RENAME TO foo_old;
ALTER TABLE foo_new RENAME TO foo;

UNLOCK TABLES;

"No data should be written or read between the LOCK and 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中,当table被"LOCK tables 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;

希望对您有所帮助。