这个问题相对简单,但是第一次遇到这种问题,仅此记录。问题主要是一个mysqldump导出也就100来M的文件,导入居然要几个小时,更换多个实例后都很慢,文件大小如下:
当然这种可以重现的问题就再次导入看看为什么就可以了。
一、问题重现和分析
导入期间的信息如下:
OS状态如下:
可以看到导入session的线程的CPU非常高。
查看show processlist状态:
查看CPU调用火焰图:
耗用CPU最多的上层调用为mysql_alter_db。问题很明显了,就是dump文件里面有大量的alter database 语句。这种语句耗用了大量的CPU,导致导入时间很长。
随后查看文件中的alter database语句大概有5600个,每个就算1秒,也要5000多秒了,因此整个导入自然就慢了。
二、为什么有这么多的ALTER DATABASE语句
实际上在进行mysqldump的时候,如果发现存储过程、自定义函数、触发器等的字符集和库的字符集不一致的时候就会调用switch_db_collation和restore_db_collation 函数,将库的字符集切换后再建立存储过程等对象,然后再将库的字符集切换回去,实际上就是多了如下的输出,
这样这些对象的字符集就是导出库一致的。
库的字符集很明显,而存储过程、自定义函数、触发器等获取的是 Database Collation:
比如:
- 当前库:utf8mb3
- 存储过程是:utf8mb4_0900_ai_ci
那么导出的语句就是:
下面是测试的片段:
可以看到在存储过程建立的前后有alter database 语句。如果有几千个这样的存储过程,虽然数据不大,但是导入却很很慢,因为耗用了太多CPU在alter database上,这些CPU耗用和导入的数据无关。
三、总结
这种问题出现,最可能的原因就是当库初始化完成后,某天用 alter database修改了库的字符集,导致导出的时候比对存储过程、自定义函数、触发器等的字符集和库的字符集不一致出现了alter database语句,如果刚好存储过程、自定义函数、触发器等很多那么就可能很慢很慢。