如何在不锁定MYSQL6.2中的表的情况下从另一个表复制数据?

时间:2016-03-04 18:59:37

标签: mysql innodb

我有一个表,其中包含Mysql服务器中的所有历史数据,并且它非常庞大(大约7亿行)。我正在创建一个具有相同列但具有分区的新表,然后我需要将旧表中的所有数据复制到新的分区表中。我已经有了正确的脚本来做到这一点,但我认为它可能锁定表。我不希望发生这种情况,因为它在生产服务器上。我该怎么办才能避免锁定桌子?

4 个答案:

答案 0 :(得分:3)

假设表格具有完全相同的列,您可以执行以下操作:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
INSERT INTO NEW_TABLE (SELECT * FROM OLD_TABLE);
COMMIT ;

我已根据Wistar's评论添加了一些其他说明。这里可以使用的读取级别是:

  • READ COMMITTED :关于一致(非锁定)读取的类似Oracle的隔离级别:即使在同一事务中,每个一致性读取也会设置并读取自己的新快照
  • READ UNCOMMITTED :SELECT语句以非锁定方式执行,但可能会使用行的早期版本。因此,使用此隔离级别,此类读取不一致。这也称为脏读。否则,此隔离级别的作用类似于READ COMMITTED。
  • REPEATABLE READ :这是InnoDB的默认隔离级别。对于一致性读取,与READ COMMITTED隔离级别存在重要差异:同一事务中的所有一致性读取读取第一次读取建立的快照。此约定意味着如果在同一事务中发出多个普通(非锁定)SELECT语句,则这些SELECT语句也相互一致。
  • SERIALIZABLE :此级别与REPEATABLE READ类似,但InnoDB隐式将所有普通SELECT语句转换为SELECT ...如果禁用自动提交,则锁定共享模式。如果启用了自动提交,则SELECT是其自己的事务。因此,已知它是只读的,并且如果作为一致(非锁定)读取执行则可以序列化,并且不需要阻止其他事务。 (要强制普通SELECT阻止其他事务已修改所选行,请禁用自动提交。)

我希望这会有所帮助。

答案 1 :(得分:0)

我不知道你的剧本是什么,但我建议你插入chucks。 See this example

如果您使用SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED,则可能会插入错误的行版本。如果你用一个选择插入所有行,那么你不仅会有锁,而且它不会是最好的表现。

您可以执行类似

的操作
 INSERT INTO NEW TABLE (SELECT * FROM OLD_TABLE LIMIT 1000 OFFSET 0 )
 INSERT INTO NEW TABLE (SELECT * FROM OLD_TABLE LIMIT 1000 OFFSET 1000 )
 INSERT INTO NEW TABLE (SELECT * FROM OLD_TABLE LIMIT 1000 OFFSET 2000 )
 ...

或使用prepare statement

CREATE PROCEDURE myproc()
BEGIN
    @rows :=0
    SELECT COUNT(*) FROM OLD_TABLE into @rows
    DECLARE i int DEFAULT 0;
    WHILE i <= @rows DO
        PREPARE stmt1 FROM 'INSERT INTO NEW TABLE (SELECT * FROM OLD_TABLE LIMIT 1000 OFFSET ? )'
        EXECUTE stmt1 USING @i;
        DEALLOCATE PREPARE stmt1;
        SET i = i + 1000;
    END WHILE;
END

当然,您可以通过更改LIMIT尺寸

来根据您的配置调整块大小

答案 2 :(得分:0)

以块的形式复制。你有MyUser AUTO_INCREMENT吗?如果是,那么

PRIMARY KEY

如果存在大量空白,或者您有其他问题,请参阅other techniques for efficiently chunking

The evils of Pagination via OFFSET

更好的是,使用Percona的 WHERE id >= $x AND id < $x + 1000 。它完成了我所描述的大部分思考, plus 它允许你在复制完成时写入表。 (它使用pt-online-schema-alter来实现它。)

答案 3 :(得分:0)

为减少使用docker build --network=host -t image_name . 的弊端,this article描述了一种在数字主键OFFSET可用时强制使用JOIN的可能方法。适当的索引。请注意,为了跟踪过程,将创建“ procedure_log”表,并在处理批处理后逐步对其进行更新:

对于MySQL:

id