7.8 KiB
7.8 KiB
UPDATE 慢查询问题修复
❌ 问题现象
导入100条数据需要很长时间,每条UPDATE需要1.5-1.6秒。
日志显示
slow sql 1608 millis. update sys_user
slow sql 1577 millis. update sys_user
slow sql 1160 millis. update sys_user
预期时间: <100ms 实际时间: 1500ms+ 慢了15倍!
🔍 问题原因
原因1:UPDATE SQL 字段重复设置(最严重)
在 SysUserMapper.xml 的 updateUser 方法中,字段设置了两次:
<!-- 第一次:340-350行 -->
<if test="prisonName != null and prisonName != ''">prison_name = #{prisonName},</if>
<if test="prisonArea != null and prisonArea != ''">prison_area = #{prisonArea},</if>
<if test="ethnicity != null and ethnicity != ''">ethnicity = #{ethnicity},</if>
<if test="educationLevel != null and educationLevel != ''">education_level = #{educationLevel},</if>
<if test="crimeName != null and crimeName != ''">crime_name = #{crimeName},</if>
<if test="sentenceTerm != null">sentence_term = #{sentenceTerm},</if>
<if test="sentenceStartDate != null">sentence_start_date = #{sentenceStartDate},</if>
<if test="sentenceEndDate != null">sentence_end_date = #{sentenceEndDate},</if>
<if test="entryDate != null">entry_date = #{entryDate},</if>
<if test="studentStatus != null and studentStatus != ''">student_status = #{studentStatus},</if>
<!-- 第二次:351-360行(重复!) -->
<if test="prisonName != null">prison_name = #{prisonName,jdbcType=VARCHAR},</if>
<if test="prisonArea != null">prison_area = #{prisonArea,jdbcType=VARCHAR},</if>
<if test="ethnicity != null">ethnicity = #{ethnicity,jdbcType=VARCHAR},</if>
<if test="educationLevel != null">education_level = #{educationLevel,jdbcType=VARCHAR},</if>
<if test="crimeName != null">crime_name = #{crimeName,jdbcType=VARCHAR},</if>
<if test="sentenceTerm != null">sentence_term = #{sentenceTerm,jdbcType=INTEGER},</if>
<if test="sentenceStartDate != null">sentence_start_date = #{sentenceStartDate,jdbcType=DATE},</if>
<if test="sentenceEndDate != null">sentence_end_date = #{sentenceEndDate,jdbcType=DATE},</if>
<if test="entryDate != null">entry_date = #{entryDate,jdbcType=DATE},</if>
<if test="studentStatus != null and studentStatus != ''">student_status = #{studentStatus},</if>
结果: 每个字段都被设置了两次,导致UPDATE执行缓慢!
原因2:数据库索引未创建
执行 optimize_import_performance_safe.sql 添加索引,提升查询速度。
原因3:远程数据库延迟
数据库在远程服务器 101.35.101.159,存在网络延迟。
✅ 解决方案
修复1:删除重复字段(已完成)
文件: SysUserMapper.xml
修改: 删除 351-360 行的重复字段设置
修改前:
<if test="studentStatus != null and studentStatus != ''">student_status = #{studentStatus},</if>
<if test="prisonName != null">prison_name = #{prisonName,jdbcType=VARCHAR},</if>
<if test="prisonArea != null">prison_area = #{prisonArea,jdbcType=VARCHAR},</if>
<!-- ...更多重复字段... -->
<if test="studentStatus != null and studentStatus != ''">student_status = #{studentStatus},</if>
update_time = sysdate()
修改后:
<if test="studentStatus != null and studentStatus != ''">student_status = #{studentStatus},</if>
update_time = sysdate()
修复2:执行数据库优化SQL
如果还没执行,请执行:
-- 文件:log/Sql/optimize_import_performance_safe.sql
-- 主要添加以下索引:
ALTER TABLE sys_user ADD INDEX idx_user_name (user_name);
ALTER TABLE sys_user ADD INDEX idx_nick_name (nick_name);
ALTER TABLE student_class ADD INDEX idx_student_id (student_id);
ALTER TABLE student_class ADD INDEX idx_student_status (student_id, status);
🚀 部署步骤
步骤1:重新编译
cd C:\Users\Administrator\Desktop\Project\ry_study-v_03\Study-Vue-redis
mvn clean package -DskipTests
步骤2:重启服务
停止旧服务,启动新服务
步骤3:执行数据库优化(如果还没执行)
在 Navicat 中连接到数据库 study,执行:
log/Sql/optimize_import_performance_safe.sql
步骤4:测试导入
- 导入100条数据
- 观察日志,查看UPDATE时间
- 确认无 "slow sql" 警告
📊 性能对比
修复前
| 指标 | 数值 |
|---|---|
| 每条UPDATE时间 | 1500ms+ |
| 100条总时间 | 2-3分钟 |
| 慢查询警告 | 每条都有 |
| SQL字段 | 重复设置 |
修复后(预期)
| 指标 | 数值 |
|---|---|
| 每条UPDATE时间 | <100ms |
| 100条总时间 | 10-30秒 |
| 慢查询警告 | 无 |
| SQL字段 | 正常 |
性能提升:15倍以上
🧪 验证方法
测试1:查看SQL执行时间
导入时查看日志,应该看到:
DEBUG c.d.s.m.S.updateUser - ==> Preparing: update sys_user SET ...
DEBUG c.d.s.m.S.updateUser - ==> Parameters: ...
DEBUG c.d.s.m.S.updateUser - <== Updates: 1
不应该有 "slow sql" 警告!
测试2:导入速度测试
# 导入100条数据
开始时间: 15:30:00
结束时间: 15:30:15
总耗时: 15秒 ✅
# 修复前需要 2-3 分钟
# 修复后只需 15-30 秒
测试3:验证SQL正确性
在日志中查看UPDATE SQL,应该是:
update sys_user
SET dept_id = ?,
user_name = ?,
...
prison_name = ?, -- 只出现一次
prison_area = ?, -- 只出现一次
...
update_time = sysdate()
where user_id = ?
每个字段只出现一次!
⚠️ 注意事项
1. 必须重新编译
Mapper 文件修改后必须重新编译,否则不生效!
mvn clean package -DskipTests
2. 必须重启服务
编译完成后必须重启服务,新的Mapper才会加载。
3. 数据库索引
如果没有执行索引SQL,性能提升不明显。
建议执行 optimize_import_performance_safe.sql。
4. 远程数据库延迟
即使优化后,远程数据库仍有网络延迟(约50-100ms/条)。 如果需要更快,考虑:
- 使用本地数据库测试
- 批量操作
- 异步处理
🔍 问题根源分析
为什么会有重复字段?
可能的原因:
- 代码合并时重复添加
- 不同开发者添加相同字段
- 复制粘贴时未删除旧代码
为什么慢?
- 重复字段: 每个字段设置两次,数据库执行时间翻倍
- 缺少索引: 没有索引的查询需要全表扫描
- 远程延迟: 网络往返时间增加
💡 优化建议
1. 代码审查
定期检查Mapper文件,避免重复字段:
# 查找重复的SET语句
grep -A 50 "<update id" mapper/*.xml | grep "SET"
2. 性能监控
启用慢查询日志,及时发现性能问题:
# application.yml
logging:
level:
com.ddnai.system.mapper: DEBUG
3. 批量操作
对于大量数据导入,使用批量操作:
// 批量INSERT
mapper.batchInsert(userList);
// 批量UPDATE
mapper.batchUpdate(userList);
📋 检查清单
- 删除重复字段
- 重新编译项目
- 重启服务
- 执行数据库优化SQL
- 测试导入100条数据
- 验证无慢查询警告
- 确认导入时间正常
✅ 总结
核心问题
UPDATE SQL 中字段重复设置两次,导致执行缓慢。
解决方法
删除重复的字段设置(351-360行)。
预期效果
- UPDATE时间从 1500ms 降到 <100ms
- 100条导入从 2-3分钟 降到 15-30秒
- 性能提升15倍以上
关键步骤
- ✅ 修改Mapper文件
- ⚠️ 重新编译
- ⚠️ 重启服务
- ⚠️ 执行索引SQL(如果还没执行)
现在重新编译并重启服务,性能应该有显著提升! 🚀