当数据迁移遇到MySql表统计分析(Cardinality)不准确的坑
最近给客户做数据迁移,850W用户的数据,在测试环境进行迁移测试,测试环境配置:红帽,物理机,32核,迁移时间80分钟左右。
生产环境配置:红帽,物理机,40核。
但是在生产上进行迁移时发现特别慢,按照速度预估需要6个小时,然后进行排查,发现数据库CPU占用率比较高,迁移程序耗费CPU不大,而在测试环境正好相反,这会已经基本上定位到问题在数据库这块,然后进过分析猜测是不是由二点问题导致:
1、没加索引
2、数据库碎片
但是进过排查发现都不是,然后我们分析数据库慢SQL发现有一条语句耗时将近2分钟,如下:
然后再次检查索引是加了索引的,然后在查看执行计划,竟然跟测试环境不一样。。。。
测试环境执行计划:
生产环境执行计划:
可以看到环境的d表没有走索引,而是进行了全表扫描。
经过分析发现是MySql的索引统计分析在捣鬼,他预估的索引唯一值Cardinality,还是按原数据进行预估为70W,这次插入了850W,当执行查询的时候,发现重复数据占比70/920=1/13,查询优化器发现重复率太高,放弃走索引,所以导致了全表扫描。
定位到问题以后执行了ANALYZE TABLE ,在测试查看执行计划与测试环境一致,问题解决。
事后查资料分析这个问题,发现网上解释都不是特别清楚,有的文章说进行insert或update的时候会触发索引统计分析,经过生产上论证不是完全准确的,因为迁移的时候对d表就会有插入操作,按说法应该更新Cardinality值,但是却没有更新。
而《高性能MySql》书中则描述表的大小超过十六分之一或者新插入20亿行会触发,很明显插入的数据超过十六分之一了,但是还是没有触发,其中书中提及的innodb_stats_sample_pages也进行了查看,与测试环境一样,默认8。
目前短时间只能搁置了,后续了解原理了在更新!