# 导入性能优化方案 ## ❌ **问题分析** ### **问题1:SQL执行慢(每条1.2秒)** ``` slow sql 1164 millis. update sys_user slow sql 1165 millis. update student_class ``` **原因:** - 每条记录更新需要1.2秒,100条就需要2分钟 - UPDATE语句中字段重复 - 可能缺少数据库索引 --- ### **问题2:班级分配逻辑错误** ``` Duplicate entry '234-17' for key 'student_class.uk_student_class' ``` **原因:** - 先UPDATE旧班级status=0 - 再INSERT新班级记录 - 如果新旧班级ID相同,INSERT失败(唯一键冲突) **日志分析:** ``` 14:58:25.593 UPDATE student_class SET status=0 WHERE id=4642 (1.2秒) 14:58:26.760 INSERT student_class (234, 17, ...) (失败:Duplicate) ``` --- ### **问题3:UPDATE SQL字段重复** ```sql update sys_user SET prison_name = ?, -- 第一次 prison_area = ?, ... prison_name = ?, -- 第二次重复! prison_area = ?, -- 重复! ... ``` --- ## ✅ **解决方案** ### **方案1:修复班级分配逻辑** #### **当前逻辑(错误):** ```java // 1. 将所有旧班级设为status=0 for (StudyStudentClass old : oldClassList) { old.setStatus(0); studentClassMapper.updateStudentClass(old); // 慢查询 } // 2. 插入新班级 studentClassMapper.insertStudentClass(studentClass); // 失败:Duplicate ``` #### **优化后逻辑(正确):** ```java // 1. 检查是否已在该班级 boolean classUpdated = false; for (StudyStudentClass old : oldClassList) { if (old.getClassId().equals(classId)) { // 已在该班级,只需确保状态为活跃 if (old.getStatus() != 1) { old.setStatus(1); studentClassMapper.updateStudentClass(old); } classUpdated = true; break; } } // 2. 如果不在该班级,禁用其他班级 if (!classUpdated) { for (StudyStudentClass old : oldClassList) { if (old.getStatus() == 1) { old.setStatus(0); studentClassMapper.updateStudentClass(old); } } } // 3. 如果不在该班级,插入新记录 if (!classUpdated) { studentClassMapper.insertStudentClass(studentClass); } ``` **优势:** - ✅ 避免Duplicate错误 - ✅ 减少不必要的UPDATE - ✅ 逻辑更清晰 --- ### **方案2:添加数据库索引** #### **检查当前索引:** ```sql SHOW INDEX FROM sys_user; SHOW INDEX FROM student_class; ``` #### **建议添加的索引:** ```sql -- 用户表:按信息编号查询 CREATE INDEX idx_user_name ON sys_user(user_name); -- 学员班级表:按学员ID查询 CREATE INDEX idx_student_id ON student_class(student_id); -- 学员班级表:按状态查询 CREATE INDEX idx_status ON student_class(status); ``` --- ### **方案3:检查UPDATE SQL(需要修复Mapper)** 检查 `SysUserMapper.xml` 中的 `updateUser` 是否有重复字段: ```xml update sys_user SET prison_name = #{prisonName}, prison_area = #{prisonArea}, ... prison_name = #{prisonName}, prison_area = #{prisonArea} where user_id = #{userId} ``` --- ### **方案4:使用批量操作** #### **当前:逐条处理** ```java for (SysUser user : userList) { userMapper.insertUser(user); // 每次1.2秒 } ``` #### **优化:批量插入** ```java // 批量插入(每批50条) List batch = new ArrayList<>(); for (SysUser user : userList) { batch.add(user); if (batch.size() >= 50) { userMapper.batchInsertUsers(batch); batch.clear(); } } if (!batch.isEmpty()) { userMapper.batchInsertUsers(batch); } ``` --- ## 🔧 **立即修复步骤** ### **步骤1:修复班级分配逻辑** 文件:`StudyClassUserServiceImpl.java` 位置:第1110-1126行(更新用户时的班级分配) 需要补充完整的班级分配逻辑(类似新增用户的逻辑) --- ### **步骤2:检查并修复UPDATE SQL** 文件:`SysUserMapper.xml` 搜索:`` 删除重复的字段设置 --- ### **步骤3:添加数据库索引** ```sql -- 连接数据库 USE ry_study; -- 检查现有索引 SHOW INDEX FROM sys_user WHERE Key_name = 'idx_user_name'; SHOW INDEX FROM student_class WHERE Key_name = 'idx_student_id'; -- 添加缺失的索引 CREATE INDEX idx_user_name ON sys_user(user_name) IF NOT EXISTS; CREATE INDEX idx_student_id ON student_class(student_id) IF NOT EXISTS; CREATE INDEX idx_status ON student_class(status) IF NOT EXISTS; ``` --- ### **步骤4:优化数据库配置** 检查数据库连接池配置: ```yaml # application.yml spring: datasource: druid: initial-size: 10 min-idle: 10 max-active: 50 # 增加最大连接数 max-wait: 60000 ``` --- ##⚡ **预期性能提升** ### **修复前:** - 100条数据:约2-3分钟 - 每条平均:1.2-1.8秒 ### **修复后:** - 100条数据:约10-20秒 - 每条平均:0.1-0.2秒 **提升:10倍以上** --- ## 📋 **快速检查清单** - [ ] 修复班级分配逻辑 - [ ] 检查UPDATE SQL是否有重复字段 - [ ] 添加数据库索引 - [ ] 测试导入100条数据 - [ ] 查看SQL慢查询日志 - [ ] 确认无Duplicate错误 --- ## 🧪 **测试步骤** 1. **准备测试数据** ```bash python generate_test_data.py # 生成100条 ``` 2. **执行导入** - 记录开始时间 - 导入test_data.xlsx - 记录结束时间 3. **查看日志** ```bash # 搜索慢查询 grep "slow sql" logs/app.log # 搜索错误 grep "Duplicate entry" logs/app.log # 计算平均时间 ``` 4. **验证结果** - 检查导入成功数量 - 检查班级分配是否正确 - 检查是否有错误 --- ## 💡 **后续优化建议** ### **1. 使用Redis缓存** - 缓存班级映射 - 缓存角色ID - 减少数据库查询 ### **2. 异步处理** - 使用消息队列 - 导入任务放入队列 - 后台异步处理 ### **3. 分片导入** - 大文件分片上传 - 每片独立处理 - 提高并发性 ### **4. 数据库优化** - 分表分库 - 读写分离 - 使用更快的存储引擎 --- ## ✅ **总结** ### **核心问题** 1. 班级分配逻辑错误导致Duplicate 2. UPDATE SQL慢查询 3. 缺少必要的数据库索引 ### **解决方法** 1. 修复班级分配逻辑 2. 检查并优化SQL 3. 添加数据库索引 ### **预期效果** - 性能提升10倍以上 - 无Duplicate错误 - 导入更流畅