소스 검색

sql优化 该方法原方法是 getUserStatisticsOld 目的为了优化sql查询 fsUserMapper.countUserStats 现拆分成三次异步查询 小程序统计功能

xgb 1 주 전
부모
커밋
a9c303cc63

+ 14 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -410,6 +410,20 @@ public interface FsUserMapper
     Map<String, Object> countUserStats(
             UserStatisticsCommonParam param);
 
+    /**
+     * 查询观看和完成人数
+     */
+    Map<String, Object> countUserWatchStats(UserStatisticsCommonParam param);
+
+    /**
+     * 统计用户答题数据(答题次数、正确次数)
+     */
+    Map<String, Object> countUserAnswerStats(UserStatisticsCommonParam param);
+
+
+    /**查询红包数量和红包金额 */
+    Map<String, Object> countUserRedPacketStats(UserStatisticsCommonParam param);
+
     /**
      * 统计用户领取红包数据(红包个数、红包金额)
      * */

+ 88 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -1190,7 +1190,95 @@ public class FsUserServiceImpl implements IFsUserService {
         return fsUserMapper.selectFsUserListByJointUserNameKey(userNameKey);
     }
 
+
+    /**
+     * @Description: 该方法原方法是 getUserStatisticsOld
+     * 目的为了优化sql查询 fsUserMapper.countUserStats 现拆分成三次异步查询
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/10/29 15:34
+     */
     private FsUserStatisticsVO getUserStatistics(UserStatisticsCommonParam param) {
+
+        FsUserStatisticsVO fsUserStatisticsVO = new FsUserStatisticsVO();
+
+        // 判断是否是管理员
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
+        if (companyUser != null && companyUser.isAdmin()){
+            param.setUserId(0L);
+            param.setCompanyId(companyUser.getCompanyId());
+        }
+
+        // 异步调用三个查询方法
+        CompletableFuture<Map<String, Object>> watchStatsFuture = CompletableFuture.supplyAsync(() ->
+                fsUserMapper.countUserWatchStats(param));
+
+        CompletableFuture<Map<String, Object>> answerStatsFuture = CompletableFuture.supplyAsync(() ->
+                fsUserMapper.countUserAnswerStats(param));
+
+        CompletableFuture<Map<String, Object>> redPacketStatsFuture = CompletableFuture.supplyAsync(() ->
+                fsUserMapper.countUserRedPacketStats(param));
+
+        try {
+            // 等待所有查询完成
+            Map<String, Object> watchMap = watchStatsFuture.get();
+            Map<String, Object> answerMap = answerStatsFuture.get();
+            Map<String, Object> redPacketMap = redPacketStatsFuture.get();
+
+            // 处理观看和完成人数统计
+            if (watchMap != null) {
+                fsUserStatisticsVO.setCourseWatchNum(Integer.valueOf(watchMap.getOrDefault("courseWatchNum", 0L).toString()))
+                        .setCourseCompleteNum(Integer.valueOf(watchMap.getOrDefault("courseCompleteNum", 0L).toString()));
+
+                Long completeNum = (Long) watchMap.get("courseCompleteNum");
+                Long watchNum = (Long) watchMap.get("courseWatchNum");
+                if (completeNum != null && watchNum != null && watchNum > 0) {
+                    int courseCompleteRate = BigDecimal.valueOf(completeNum)
+                            .divide(BigDecimal.valueOf(watchNum), 2, RoundingMode.HALF_UP)
+                            .multiply(BigDecimal.valueOf(100))
+                            .intValue();
+                    fsUserStatisticsVO.setCourseCompleteRate(courseCompleteRate);
+                }
+            }
+
+            // 处理答题统计
+            if (answerMap != null) {
+                Long answerRightNum = (Long) answerMap.get("answerRightNum");
+                Long answerNum = (Long) answerMap.get("answerNum");
+
+                fsUserStatisticsVO.setAnswerNum(answerNum.intValue()).setAnswerRightNum(answerRightNum.intValue());
+
+                if (answerRightNum != null && answerNum != null && answerNum > 0) {
+                    int answerCompleteRate = BigDecimal.valueOf(answerRightNum)
+                            .divide(BigDecimal.valueOf(answerNum), 2, RoundingMode.HALF_UP)
+                            .multiply(BigDecimal.valueOf(100))
+                            .intValue();
+                    fsUserStatisticsVO.setAnswerRightRate(answerCompleteRate);
+                }
+            }
+
+            // 处理红包统计
+            if (redPacketMap != null) {
+                Object numObj = redPacketMap.get("redPacketNum");
+                Object amtObj = redPacketMap.get("redPacketAmount");
+                if (numObj != null && amtObj != null) {
+                    fsUserStatisticsVO.setRedPacketNum(Integer.parseInt(numObj.toString()))
+                            .setRedPacketAmount(new BigDecimal(amtObj.toString()));
+                }
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            // 异常处理
+            logger.error("异步查询用户统计数据失败", e);
+        }
+
+        return fsUserStatisticsVO;
+    }
+
+
+
+
+    private FsUserStatisticsVO getUserStatisticsNew(UserStatisticsCommonParam param) {
         FsUserStatisticsVO fsUserStatisticsVO = new FsUserStatisticsVO();
 
         // 判断是否是管理员

+ 100 - 0
fs-service/src/main/resources/mapper/his/FsUserMapper.xml

@@ -1206,6 +1206,106 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
 
 
+    <!-- 查询观看和完成人数 -->
+    <select id="countUserWatchStats" resultType="Map">
+        SELECT
+        COUNT(DISTINCT CASE WHEN l.log_type != 3 AND l.send_type = 1 THEN l.user_id END) AS courseWatchNum,
+        COUNT(DISTINCT CASE WHEN l.log_type = 2 AND l.send_type = 1 THEN l.user_id END) AS courseCompleteNum
+        FROM  fs_course_watch_log l
+        LEFT JOIN fs_user u  ON u.user_id = l.user_id
+        LEFT JOIN company_user cu_l ON l.company_user_id = cu_l.user_id
+        <where>
+            <if test="userId != null and userId != 0">
+                AND (cu_l.user_id = #{userId} OR cu_l.parent_id = #{userId})
+            </if>
+            <if test="userId != null and userId == 0">
+                AND l.company_id = #{companyId}
+            </if>
+            <if test="periodId != null and periodId != ''">
+                AND l.period_id = #{periodId}
+            </if>
+            <if test="videoId != null and videoId != ''">
+                AND l.video_id = #{videoId}
+            </if>
+            <if test="startTime != null and startTime != ''">
+                AND l.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime != ''">
+                AND l.create_time &lt;= #{endTime}
+            </if>
+            <if test="companyUserId != null and companyUserId != ''">
+                AND l.company_user_id = #{companyUserId}
+            </if>
+        </where>
+    </select>
+
+    <!-- 查询答题人数和答对人数 -->
+    <select id="countUserAnswerStats" resultType="Map">
+        SELECT
+        COUNT(DISTINCT CASE WHEN a.user_id THEN a.user_id END) AS answerNum,
+        COUNT(DISTINCT CASE WHEN a.is_right = 1 THEN a.user_id END) AS answerRightNum
+        FROM  fs_course_answer_logs a
+        LEFT JOIN fs_user u  ON u.user_id = a.user_id
+        LEFT JOIN company_user cu_a ON a.company_user_id = cu_a.user_id
+        <where>
+            <if test="userId != null and userId != 0">
+                AND (cu_a.user_id = #{userId} OR cu_a.parent_id = #{userId})
+            </if>
+            <if test="userId != null and userId == 0">
+                AND a.company_id = #{companyId}
+            </if>
+            <if test="periodId != null and periodId != ''">
+                AND a.period_id = #{periodId}
+            </if>
+            <if test="videoId != null and videoId != ''">
+                AND a.video_id = #{videoId}
+            </if>
+            <if test="startTime != null and startTime != ''">
+                AND a.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime != ''">
+                AND a.create_time &lt;= #{endTime}
+            </if>
+            <if test="companyUserId != null and companyUserId != ''">
+                AND a.company_user_id = #{companyUserId}
+            </if>
+        </where>
+    </select>
+
+    <!-- 查询红包数量和红包金额 -->
+    <select id="countUserRedPacketStats" resultType="Map">
+        SELECT
+        COUNT(CASE WHEN flog.status = 1 THEN flog.log_id END) AS redPacketNum,
+        IFNULL(SUM(CASE WHEN flog.status = 1 THEN flog.amount END), 0) AS redPacketAmount
+        FROM  fs_course_red_packet_log flog
+        LEFT JOIN fs_user u  ON u.user_id = flog.user_id
+        LEFT JOIN company_user cu_flog ON flog.company_user_id = cu_flog.user_id
+        <where>
+            <if test="userId != null and userId != 0">
+                AND (cu_flog.user_id = #{userId} OR cu_flog.parent_id = #{userId})
+            </if>
+            <if test="userId != null and userId == 0">
+                AND flog.company_id = #{companyId}
+            </if>
+            <if test="periodId != null and periodId != ''">
+                AND flog.period_id = #{periodId}
+            </if>
+            <if test="videoId != null and videoId != ''">
+                AND flog.video_id = #{videoId}
+            </if>
+            <if test="startTime != null and startTime != ''">
+                AND flog.create_time &gt;= #{startTime}
+            </if>
+            <if test="endTime != null and endTime != ''">
+                AND flog.create_time &lt;= #{endTime}
+            </if>
+            <if test="companyUserId != null and companyUserId != ''">
+                AND flog.company_user_id = #{companyUserId}
+            </if>
+        </where>
+    </select>
+
+
     <select id="countUserAnswer" resultType="Map">
         SELECT
         (