mysql 5.6.50,5.7 版本 索引碎片化导致服务器cpu骤增问题

在二开和运维途中将一张数据200多万的表的一个无用字段修改了类型和名称之后发现在job+rabbitmq 大批量对这个表进行查询修改增加的时候出现了服务器cpu骤增的情况

我的服务器配置是4核16GB的Ubuntu 20

这个问题让博主也是头疼了两天,不知道改如何解决这个问题。

我先是修改了线上数据库mysql5.6.50的配置文件

增加了innodb的缓存 innodb_buffer_pool_size 1024M->2048M
innodb_log_file_size 512M->1024M和innodb_log_buffer_size 128M->256M也对应增加了一倍,还将innodb_thread_concurrency :8 调整到了16

配置修改如下:

sql 复制代码
innodb_buffer_pool_size = 2048M
innodb_log_file_size = 1024M
innodb_log_buffer_size = 256M
innodb_thread_concurrency = 16
然后修改了对应的job在给队列推送消息的时候每次从数据库取1000条 延时500ms再发送下一条,目前增加了对应的List.clear防止for中List多创建
java 复制代码
 int pageCount = total / BATCH_SIZE + (total % BATCH_SIZE != 0 ? 1 : 0);
        Page<ReadMeterParamsVo> page = new Page<>();
        page.setSize(BATCH_SIZE);
        for (int i = 1; i <= pageCount; i++) {
            page.setCurrent(i);
            IPage<ReadMeterParamsVo> meterIPage = customerService.getReadMeterList(page, queryWrapper);
            for (ReadMeterParamsVo readMeterParamsVo : meterIPage.getRecords()) {
                rabbitMqClient.sendMessage(READ_METER_CONSUME_QUEUE,readMeterParamsVo);
            }
            log.info("本次加入队列数(第{}批):{}", i,meterIPage.getRecords().size());
            // 这样就不会每次创建一个IPage对象了,而是复用一个IPage对象
            meterIPage.getRecords().clear();
            if(i < pageCount){
                try {
                    Thread.sleep(BATCH_INTERVAL);
                } catch (InterruptedException e) {
                    log.error("线程休眠异常",e);
                }
            }
        }

我的消费者设置了12-16个根据消息的多少4个消费者设置的都是 concurrency = "3-4",取文件是prefetch 4,没有修改定时任务所对应表字段的时候,抄表时mysql cpu占比是4.6%,修改之后cpu占比是99%,并且我的sql慢查询日志也没有

然后又想到了mysql索引碎片化,如是使用下面脚本查询一下数据库对应表的碎片率和空闲空间

sql如下

sql 复制代码
-- 查询数据库所有表的
SELECT 
  TABLE_NAME,
  DATA_FREE/1024/1024 AS DATA_FREE_MB,  -- 空闲空间(MB)
  (DATA_FREE/(DATA_LENGTH+INDEX_LENGTH))*100 AS FRAGMENT_RATE  -- 碎片率(%)
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_SCHEMA = 'smart_water';
sql 复制代码
-- 查询出索引碎片化大于10%的表
SELECT 
  TABLE_NAME,
  -- 保留2位小数,显示空闲碎片空间(MB)
  ROUND(DATA_FREE/1024/1024, 2) AS DATA_FREE_MB,
  -- 保留2位小数,计算碎片率,避免除以0
  ROUND(IF((DATA_LENGTH+INDEX_LENGTH)=0, 0, (DATA_FREE/(DATA_LENGTH+INDEX_LENGTH))*100), 2) AS FRAGMENT_RATE
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_SCHEMA = 'smart_water' 
  -- 筛选碎片率>10%的表,兼容5.6
  AND IF((DATA_LENGTH+INDEX_LENGTH)=0, 0, (DATA_FREE/(DATA_LENGTH+INDEX_LENGTH))*100) > 10
  -- 排除视图/空表,仅保留InnoDB/MyISAM表
  AND TABLE_TYPE = 'BASE TABLE' 
  AND DATA_LENGTH > 0;
对碎片化大于30%的表使用OPTIMIZE TABLE重建所有索引 + 整理表碎片,对于小一点的使用 ANALYZE TABLE更新索引统计信息(如行数、字段分布)

下面是两个sql的区别

操作 核心作用 锁表情况 耗时(百万行表) 适用场景
ANALYZE TABLE 更新索引统计信息(如行数、字段分布) 无锁/极低锁(几乎不阻塞业务) 几秒 1. 修改字段后; 2. 数据大量增删后; 3. 优化器选错索引
OPTIMIZE TABLE 重建所有索引 + 整理表碎片 短时间锁表(InnoDB 5.6+支持在线) 几十秒~几分钟 1. 索引碎片率极高(>30%); 2. 表数据频繁删除后空间浪费; 3. 索引损坏

使用就是 OPTIMIZE TABLE 表名,表名 和 ANALYZE TABLE 表名,表名

目前数据库配置和索引碎片化已经整理了,就期待明天的定时抄表任务cpu占比效率了

如果大佬还有其他的方法能解决这个mysql cpu突然飙升的问题,欢迎评论区留言

相关推荐
广州灵眸科技有限公司3 小时前
xfce桌面触摸校准:基于灵眸科技EASY-EAl-Orin-Nano
数据库·windows·科技
Cloud云卷云舒5 小时前
云卷云舒:从Oracle/MySQL迁移到HaishanDB:迁移评估工具核心技术拆解
mysql·oracle·ai-native·haishandb·信创数据库替换
憧憬成为web高手5 小时前
皮卡丘靶场速通--sql 2
数据库·sql·mybatis
段一凡-华北理工大学6 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
oradh8 小时前
Oracle XTTS实现跨版本迁移和升级(Oracle 11g单库升级至19C RAC集群)
数据库·oracle·11g升级19c·xtts跨版本迁移和升级
用户71333585156248 小时前
MySQL - 事务、redo/undo 日志与 MVCC
mysql
z123456789868 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
程序猿DD9 小时前
一个 API Key,统一调用大模型、生图和联网搜索
数据库·网关
java_logo9 小时前
Docker Compose 部署 ClickHouse:快速搭建高性能列式数据库
数据库·clickhouse·docker·列式数据库·轩辕镜像·高性能数据库·clickhouse部署教程
用户71333585156249 小时前
MySQL - InnoDB 的 Buffer Pool
mysql