美文网首页
手工重现Mysql插入的"2.6亿"垃圾数据

手工重现Mysql插入的"2.6亿"垃圾数据

作者: 码代码的陈同学 | 来源:发表于2018-06-11 22:49 被阅读0次

    欢迎访问 陈同学博客原文

    本文是昨天 Mysql插入2.6亿条垃圾数据后会发生什么? 的续篇,将模拟生产环境情况,加深对问题的理解,探索更多解决方式,同时也更多的了解下mysql kill命令。

    重现准备

    基于Mysql 5.7.22,在一个事务内,利用存储过程往测试表中插入1千万记录,在此过程中进行kill mysql threaddrop table 等操作。

    测试表和过程对应的SQL可见本文最后的附录。

    开始重现

    执行存储过程,插入数据

    执行存储过程之后,事务中处理的记录数高速增长。

    image

    对表执行DDL操作

    在上述事务 inserting 期间,对表执行 truncatedrop,通过show processlist结果如下:

    drop table test

    image

    truncate table test

    image

    上面两个操作的结果都是: Waiting for table metadata lock

    如果你想了解什么是 Metadata lock,可以查阅官网文档 Metadata Locking

    kill mysql thread

    在插入850W记录后,表容量扩展到1G,CPU和内存被mysqld基本耗尽.

    现在,kill 下图中 mysql thread 12,事务进入 ROLLING BACK 状态。同时,在PROCESSLIT中会发现该线程已消失。

    image

    rollback 期间,对表做任何DDL操作其实和 inserting 期间是一样的。

    restart mysql

    在上述 rollback 期间,停止Mysql,再重启。Mysql会继续事务的回滚(ps:其实不用想,这是肯定的,否则无法保障数据一致性需求)

    理解mysql kill

    参考 KILL Syntax

    kill的使用

    每一个连接到 mysqld 的 connection都将使用独立的 thread 来运行。可以使用 kill 命令来杀死thread.

    通过 show processlist 查看当前线程,下图中的ID字段即 mysql thread id.

    该命令与查询 processlist 表的效果一样

    image

    kill 提供了两个选项:

    • kill connection:将关闭连接,默认使用该选项。eg: kill 1kill connection 1效果一样
    • kill query:中断当前连接正在执行的SQL,但是连接不会关闭,可以继续使用, eg: kill query 1

    kill的原理

    使用kill命令处理mysql thread时,将会为这个thread设置一个kill flag。在大多数情况下,线程可能需要一些时间才能被killed,因为mysql会以特定的间隔来检查设置了 kill flag 的thread并将其kill.

    关于kill flag在各种操作期间的检查情况,可以参考 KILL Syntax

    小结

    本文虽然重现了问题的过程,但其实并未解决问题。后续将继续分享以下几个知识点,作为本次事件的续篇。

    • kill mysql thread后事务的处理机制?
    • InnoDB redo/undo机制以实现事务并保障数据的一致性
    • redo/undo buffer是如何耗尽内存的?
    • mysql 常见锁的排查流程

    附录

    测试表

    包含主键和3个普通字段,将使用mysql uuid()赋值

    CREATE TABLE test.test (
      id INT(11) NOT NULL AUTO_INCREMENT,
      uid CHAR(36) DEFAULT NULL,
      uid2 CHAR(36) DEFAULT NULL,
      uid3 CHAR(36) DEFAULT NULL,
      PRIMARY KEY (id)
    )
    ENGINE = INNODB;
    

    测试的存储过程

    存储过程运行1千万次,在运行过程中将中断执行。

    CREATE DEFINER = 'test'@'%'
    PROCEDURE test.test()
    BEGIN
    DECLARE i INT;
     
    START TRANSACTION;
    SET i = 1;
    
    REPEAT
    INSERT INTO test (uid, uid2, uid3)
      VALUES (UUID(), UUID(), UUID());
     
    SET i = i + 1;
    
    UNTIL i >= 10000000
    END REPEAT;
    
    COMMIT ;
     
    END
    

    相关文章

      网友评论

          本文标题:手工重现Mysql插入的"2.6亿"垃圾数据

          本文链接:https://www.haomeiwen.com/subject/vgekeftx.html