AI 负责发现问题,人负责判断优先级。一次 Claude Code 辅助性能优化的完整记录,附 Prompt 原文和 17 个问题清单。
我用 Claude Code 审查了一个有 300 万行数据的日志模块。AI 在两分钟内列出了 17 个性能问题,我花了 4 小时筛选出 6 个最值得修改的并实施。最终查询响应从 3 秒降到 200ms。整个过程的核心不是“AI 帮我写了多少代码”,而是“AI 帮我找到了问题,我来判断哪些该改”。
摘要
本文记录了使用 Claude Code 对拥有 300 万行数据的日志模块进行性能优化的完整过程。通过精心设计的 Prompt 和项目约束文件,AI 在 2 分钟内识别出 17 个性能问题,作者从中筛选出 6 个高价值问题并修复。优化后,查询响应时间从 2-3 秒降至 200-300 ms,性能提升显著。文章分享了 AI 辅助开发的核心经验:AI 擅长快速发现问题,而人类需要负责判断优先级和决策实施。
SEO 摘要
本文记录了使用 Claude Code 对 Java 17 + Spring Boot 3 + MyBatis-Plus + MySQL 8 技术栈的 300 万行日志模块进行性能优化的完整实践。AI 在 2 分钟内识别出 17 个性能问题,作者按投入产出比筛选 6 个高价值项实施修复,最终查询响应从 2-3 秒降至 200-300ms。文章核心经验:AI 擅长快速发现问题,人类负责判断优先级与决策——Prompt 越具体、约束越明确,AI 辅助效果越好。
背景
我们的系统里有一个日志查询模块,数据量接近 300 万条。上线初期体验尚可,但随着数据增长,翻页操作越来越慢——平均响应时间已达到 2 到 3 秒,高峰期甚至超过 5 秒。运营那边开始频繁反馈“页面卡住了”。
手头需求排得很紧,抽不出半天时间做专项优化。想到 Claude Code 能直接读取项目代码进行分析,就决定先让它跑一轮审查,看看能否快速定位瓶颈。
怎么让 AI 帮我
Claude Code 是 Anthropic 推出的命令行 AI 编程助手,能直接读取项目代码并给出分析。用过 Copilot 的同学可以把它理解为一个“能看懂整个项目上下文的终端助手”。
关键一步是在项目根目录放置一个AGENTS.md文件,把技术栈和约束告诉 AI,避免它给出不切实际的建议:
# 项目约束 技术栈: Java 17 + Spring Boot 3 + MyBatis-Plus + MySQL 8 + Redis + RabbitMQ ORM: MyBatis-Plus 3.5.x,不要建议换 Hibernate 构建工具: Maven 日志模块路径: log-service/src/main/java/com/xxx/log/ 约束: - 不要引入新依赖,除非有必要且轻量 - SQL 变更需要兼容现有索引 - 线上 MySQL 版本 8.0.35,不要用新特性然后启动 Claude Code,给它一条指令:
@log-service 请审查 log-service 模块的代码,重点关注性能问题。 按 P0(必须修)/ P1(建议修)/ P2(可选优化)分级列出, 每个问题给出:现象、根因分析、建议修复方案。 最后给出一个优先级排序的总结。这条指令的核心技巧:限定范围(log-service 模块)、限定关注点(性能)、要求分级(P0/P1/P2)、要求结构化输出(现象 + 根因 + 方案)。
AI 发现了什么
大概过了两分钟,Claude 返回了17 个问题。我逐条看了一遍,整体质量比预期高——大部分问题的根因分析是准确的,建议方案也可行。
下面是精简后的问题汇总:
| 级别 | 数量 | 核心问题 |
|---|---|---|
| P0 | 3 | COUNT(*)无 LIMIT 导致全表扫描;排序字段直接拼接 SQL 存在注入风险;分页查询未覆盖索引 |
| P1 | 7 | 异步线程池无界队列;字典翻译存在 N+1 查询;AOP 切面中执行重 IO 操作;大事务未拆分等 |
| P2 | 7 | 日志级别过细、MyBatis prefetch 未调优、部分可合并的 MQ 消息未合并等 |
P0 的问题最致命——COUNT(*)没加 LIMIT,MySQL 在 300 万行的表上直接全表扫描,这就是翻页慢的直接原因。排序字段用String.format拼接 SQL 而非使用参数化查询,虽然是内部系统,但注入风险依然存在。
P1 的问题属于“现在不修,迟早要修”的范畴。线程池使用LinkedBlockingQueue默认的 Integer.MAX_VALUE 容量,高并发下内存可能被打爆;字典翻译在循环里逐条查询,10 个字段就是 10 次 SQL。
下面是从 AI 发现问题到人工筛选实施的完整决策流程图:
该流程图展示了从 AI 发现问题到人工筛选、实施、验证的完整闭环,突出了分级、筛选标准和最终实施的关键环节。
我决定改什么
17 个问题不可能一次全改完,我按“投入产出比”挑了 6 个影响最大的:
- COUNT 加 LIMIT 1— 分页查询前不再执行
COUNT(*)全表扫描,改为SELECT COUNT(*) FROM (SELECT 1 FROM table LIMIT 1) t或用 Redis 缓存近似值。仅此一项,查询就从 3s 降到 200ms。 - 排序字段白名单校验— 用 MyBatis-Plus 的
TableInfoHelper验证排序字段名是否合法,彻底消除 SQL 注入风险。 - 字典查询批量化— 把循环里逐条查询字典改为
IN批量查询,10 次 SQL 合并成 1 次。 - 线程池改有界队列—
LinkedBlockingQueue改为ArrayBlockingQueue(200),配合 CallerRunsPolicy 拒绝策略,防止内存溢出。 - 重 IO 操作迁到异步线程— AOP 切面里的日志写入和指标上报操作迁到线程池异步执行,减少主线程阻塞。
- MQ ACK 改手动确认 + DLQ— 消息消费改为手动 ACK,消费失败进入死信队列,避免消息丢失又排查不到。
实际编码大概花了 4 个小时,其中一半时间在测试验证。Claude Code 的建议省去了我最耗时的“定位问题”阶段。
效果
2-3s → 200-300ms(优化前后平均响应时间)
上线后观察一周,主要收益:
- 日志查询页面响应时间从 3s 降到 300ms,体验上从"要等"变成"秒开"
- 高峰期不再出现“页面卡住”的反馈
- MQ 消费失败的消息进入 DLQ 后可追溯,之前丢失的两周日志总算有线索了
- 线程池内存占用稳定在合理区间,不再出现过 GC 压力大的告警
一点感受
这次经历给我的最大感触是:AI 在"发现问题"这个环节确实比人快。17 个问题,我自己排查可能需要大半天时间,Claude Code 两分钟就列出来了,而且准确率不错。
但"发现问题"只是第一步。17 个问题哪些该改、哪些可以延后、改了会不会引入新问题——这些判断还是得由人来做。比如 P2 里的日志级别调优,改动小但收益也小,在当前阶段不值得投入。
回到开头那句话:AI 帮我找到了问题,我来判断哪些该改。这可能是 AI 辅助开发最真实的工作模式——不是 AI 替你干活,而是 AI 帮你看得更远,你来决定往哪走。Prompt 越具体,AI 看得越清楚。别扔一句“帮我优化代码”就指望好结果——告诉它技术栈、限定范围、明确输出格式,效果会好很多。
后续监控与调优
优化上线不是终点,持续监控才能确保效果持久。以下是本次优化后建立的几条监控机制和未来规划:
慢 SQL 日志分析:线上开启了 MySQL 慢查询日志(阈值设为 200ms),配合
pt-query-digest工具每周自动生成慢 SQL 报表并推送到企业微信群。如果发现新的慢查询,可以直接丢给 Claude Code 让它先做一轮分析,把“人肉排查”变成“AI 先筛一遍”。APM 全链路监控:接入了 SkyWalking(开源版即可),在查询接口和 MQ 消费入口打了自定义埋点,重点监控 P99 响应时间、MQ 延迟和线程池队列堆积量。面板上设了告警阈值:接口 P99 超过 500ms 或线程池队列积压超过 150 就自动通知——这次优化后,这些指标至少帮我们在三次小故障爆发前提前发现了问题。
JVM 指标兜底:线程池改有界后,把
ThreadPoolExecutor的getQueue().size()和getActiveCount()以每分钟频率上报到 Prometheus,配合 Grafana 面板可视化。同时监控 GC 频率和老年代内存,防止线程池调整后连带引发 GC 问题。
如果日志模块的数据量继续增长到千万级别,当前的单表方案迟早会碰到瓶颈。后续有两个方向可以提前评估:
- 读写分离:日志查询属于典型的“写多读少但读对延迟敏感”场景,把查询打到只读从库可以减轻主库压力,配合 MyBatis-Plus 的多数据源配置实现成本不高。
- 分库分表:当单表超过 2000 万行时,即使索引优化到位,复杂度也会上来。初步考虑按日志时间按月分表,查询时带上时间范围路由,配合 ShardingSphere 做透明分片,避免业务代码大改。