首页 > 其他分享 >数据统计查询优化

数据统计查询优化

时间:2024-07-28 22:30:46浏览次数:10  
标签:map begin end int dateList 查询 优化 统计

数据统计查询优化

当前项目中存在的问题

当前的数据统计模块中,营业额统计、用户统计和订单统计这三个接口的在业务层中的运行流程如下:

  1. 根据前端传来的起止日期计算期间每一天的日期并存入日期集合。
  2. 遍历日期集合得到每一天的日期,将该日期处理后再查询数据库中当天满足条件的数据。
  3. 将每次查询的结果进行处理后存入相应的结果集合。
  4. 将结果集合进行封装后返回。

在第二步中,查询的日期有几天,就会查询几次数据库,同时每次查询的数据量有很小。而比起数据库的查询操作本身,与数据库的连接非常耗费时间。这种做法无疑回导致性能大幅下降。

解决方案

每个接口都只与数据库进行一次连接,在这一次连接中查询出所有需要的数据,然后在Java中进行处理并返回。具体步骤如下:

  1. 根据前端传来的起止日期计算期间每一天的日期并存入日期集合。
  2. 查询起止日期范围内所有满足条件的数据。
  3. 将查询到的数据进行处理并封装返回。

代码开发

营业额统计

  • 在ReportServiceImpl中修改getTurnoverStatistics方法:
@Override
public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
    List<LocalDate> dateList = getDateList(begin, end); //当前集合用于存放从begin到end范围内每天的日期
    BigDecimal[] turnoverList = new BigDecimal[dateList.size()]; //当前集合用于存放从begin到end范围内每天的营业额

    Arrays.fill(turnoverList, BigDecimal.ZERO); //初始化营业额数组

    //查询从begin到end范围内状态为已完成的所有订单数据
    Map map = new HashMap<>();
    map.put("begin", LocalDateTime.of(begin, LocalTime.MIN));
    map.put("end", LocalDateTime.of(end, LocalTime.MAX));
    map.put("status", Orders.COMPLETED);
    List<Orders> ordersList = orderMapper.getByMap(map);

    //把查出来的订单的营业额加上
    for (Orders orders : ordersList) {
        LocalDate orderTime = orders.getOrderTime().toLocalDate();
        int period = Period.between(begin, orderTime).getDays();
        turnoverList[period] = turnoverList[period].add(orders.getAmount());
    }

    //将集合转换为字符串
    String dateListString = StringUtils.join(dateList, ",");
    String turnoverListString = StringUtils.join(turnoverList, ",");

    //构造TurnoverReportVO并返回
    TurnoverReportVO turnoverReportVO = TurnoverReportVO.builder()
            .dateList(dateListString)
            .turnoverList(turnoverListString)
            .build();
    return turnoverReportVO;
}
  • 在OrderMapper接口中声明getByMap方法:
List<Orders> getByMap(Map map);
  • 在OrderMapper.xml中编写getByMap方法的SQL语句:
<select id="getByMap" resultType="com.sky.entity.Orders">
    select * from orders
    <where>
        <if test="begin != null">
            and order_time &gt; #{begin}
        </if>
        <if test="end != null">
            and order_time &lt; #{end}
        </if>
        <if test="status != null">
            and status = #{status}
        </if>
    </where> order by order_time asc
</select>

用户统计

  • 在ReportServiceImpl中修改getUserStatistics方法:
@Override
public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
    List<LocalDate> dateList = getDateList(begin,end); //当前集合用于存放从begin到end范围内每天的日期
    int[] totalUserList = new int[dateList.size()]; //当前集合用于存放从begin到end范围内每天的总用户数
    int[] newUserList = new int[dateList.size()]; //当前集合用于存放从begin到end范围内每天新增的用户数

    //查询注册时间在begin到end范围内的所有用户数据
    List<User> userList = userMapper.getByBeginAndEndTime(
            LocalDateTime.of(begin, LocalTime.MIN),
            LocalDateTime.of(end, LocalTime.MAX));

    //根据查询到的用户数据计算每天的新增用户数
    for (User user : userList) {
        LocalDate createTime = user.getCreateTime().toLocalDate();
        int period = Period.between(begin, createTime).getDays();
        newUserList[period]++;
    }

    //查询begin时间之前的总用户数
    Map map = new HashMap<>();
    map.put("end", LocalDateTime.of(begin, LocalTime.MIN));
    Integer totalUser = userMapper.countByMap(map);

    //计算每天的总用户数
    totalUserList[0] = totalUser + newUserList[0];
    for (int i = 1; i < dateList.size(); i++) {
        totalUserList[i] = totalUserList[i - 1] + newUserList[i];
    }

    //将集合转换为字符串
    String dateListString = StringUtils.join(dateList, ",");
    String totalUserListString = StringUtils.join(totalUserList, ',');
    String newUserListString = StringUtils.join(newUserList, ',');

    //构造UserReportVO并返回
    UserReportVO userReportVO = UserReportVO.builder()
            .dateList(dateListString)
            .totalUserList(totalUserListString)
            .newUserList(newUserListString)
            .build();
    return userReportVO;
}
  • 在OrderMapper接口中声明getByBeginAndEndTime方法:
List<User> getByBeginAndEndTime(LocalDateTime begin, LocalDateTime end);
  • 在OrderMapper.xml中编写getByBeginAndEndTime方法的SQL语句:
<select id="getByBeginAndEndTime" resultType="com.sky.entity.User">
    select * from user
    <where>
        <if test="begin != null">
            and create_time &gt; #{begin}
        </if>
        <if test="end != null">
            and create_time &lt; #{end}
        </if>
    </where>
</select>

订单统计

  • 在ReportServiceImpl中修改getOrdersStatistics方法:
@Override
public OrderReportVO getOrdersStatistics(LocalDate begin, LocalDate end) {
    List<LocalDate> dateList = getDateList(begin, end); //当前集合用于存放从begin到end范围内每天的日期
    int[] orderCountList = new int[dateList.size()]; //当前集合用于存放从begin到end范围内每天的订单数
    int[] validOrderCountList = new int[dateList.size()]; //当前集合用于存放从begin到end范围内每天的有效订单数

    //查询从begin到end范围内的所有订单数据
    Map map = new HashMap<>();
    map.put("begin", LocalDateTime.of(begin, LocalTime.MIN));
    map.put("end", LocalDateTime.of(end, LocalTime.MAX));
    List<Orders> ordersList = orderMapper.getByMap(map);

    //把查出来的订单数以及已完成的订单数加上
    for (Orders orders : ordersList) {
        LocalDate orderTime = orders.getOrderTime().toLocalDate();
        int period = Period.between(begin, orderTime).getDays();
        orderCountList[period]++;
        if (orders.getStatus().equals(Orders.COMPLETED)) {
            validOrderCountList[period]++;
        }
    }

    Integer totalOrderCount = Arrays.stream(orderCountList).reduce(Integer::sum).getAsInt(); //计算订单总数
    Integer validOrderCount = Arrays.stream(validOrderCountList).reduce(Integer::sum).getAsInt(); //计算有效订单总数
    Double orderCompletionRate = totalOrderCount == 0 ? 0.0 : validOrderCount.doubleValue() / totalOrderCount; //计算订单完成率

    //将集合转换为字符串
    String dateListString = StringUtils.join(dateList, ",");
    String orderCountListString = StringUtils.join(orderCountList, ',');
    String validOrderCountListString = StringUtils.join(validOrderCountList, ',');

    //构造OrderReportVO并返回
    OrderReportVO orderReportVO = OrderReportVO.builder()
            .dateList(dateListString)
            .orderCountList(orderCountListString)
            .validOrderCountList(validOrderCountListString)
            .totalOrderCount(totalOrderCount)
            .validOrderCount(validOrderCount)
            .orderCompletionRate(orderCompletionRate)
            .build();
    return orderReportVO;
}

功能测试

  • 通过接口文档测试方法的执行时间(测试时查询近30日数据),如下表所示:
接口 优化前执行时间 优化后执行时间
营业额统计 98ms 37ms
用户统计 117ms 4ms
订单统计 112ms 9ms
  • 通过前后端联调测试验证了方法的正确性。

标签:map,begin,end,int,dateList,查询,优化,统计
From: https://www.cnblogs.com/zgg1h/p/18328963

相关文章

  • 缓存优化(缓存穿透)
    缓存优化(缓存穿透)缓存穿透缓存穿透是指查询一个一定不存在的数据时,数据库查询不到数据,也不会写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,可能导致数据库崩溃。这种情况大概率是遭到了攻击。常见的解决方案有:缓存空数据,使用布隆过滤器等。当前项目中存在的......
  • SQL Server慢查询日志
    如何让SQLServer像MySQL一样拥有慢查询日志(SlowQueryLog慢日志)如何让SQLServer像MySQL一样拥有慢查询日志(SlowQueryLog慢日志)SQLServer一直以来被人诟病的一个问题是缺少了像MySQL的慢日志功能,程序员和运维无法知道数据库过去历史的慢查询语句。因为SQLServer默认是不捕......
  • 多元统计分析
    多元统计分析目录多元统计分析定义研究对象:多维随机变量研究内容:多元统计数据的图表示法多元统计分析的简单指标定义研究多个随机变量之间相互依赖关系以及内在统计规律性的理论和统计方法的总称。研究对象:多维随机变量研究内容:降维问题「主成分分析、因子分析......
  • IDEA的常用配置和优化
    文章目录IDEA的常用配置和优化IntelliJIDEA版本:2019.2.3永久破解需要以下两个破解文件选择Evaluateforfree(试用)启动IDEA,在启动界面上点击Configure-->EditCustomVMOptions...重置Idea试用开始时间重置插件安装重置插件设置idea性能优化--自定义虚拟机内存Ma......
  • 深度模型中的优化 - 基本算法篇
    序言在深度学习中,模型优化是提升模型性能与训练效率的关键环节。深度模型通过优化算法不断调整其内部参数,以最小化损失函数,从而实现对复杂数据的有效拟合与预测。本篇章将简要概述深度模型中的几种基本优化算法,包括梯度下降法及其变种,这些算法在推动深度学习领域的发展中起......
  • LeetCode_sql_day07(579. 查询员工的累计薪水,2173.最多连胜的次数)
    描述:579.查询员工的累计薪水编写一个解决方案,在一个统一的表中计算出每个员工的 累计工资汇总 。员工的 累计工资汇总 可以计算如下:对于该员工工作的每个月,将 该月 和 前两个月 的工资 加 起来。这是他们当月的 3个月总工资和 。如果员工在前几个月没有为公......
  • [附开题]flask框架的全国汽车销售信息查询系统的设计与实现7m1w0(python+源码)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着中国汽车市场的蓬勃发展,汽车品牌的日益丰富以及消费者购车需求的多样化,汽车销售信息的准确性与时效性成为了市场关注的焦点。传统汽车......
  • JVM垃圾回收器和优化
    JVM(JavaVirtualMachine)垃圾回收器(GarbageCollector,GC)是Java内存管理中的重要组成部分,负责自动回收不再被使用的内存空间,以防止内存泄露和内存溢出。同时,JVM的优化也是提高Java应用程序性能的重要手段。以下将详细介绍JVM垃圾回收器的种类以及JVM的优化方法。一、JVM垃圾......
  • Catalyst优化器:让你的Spark SQL查询提速10倍
    目录1逻辑优化阶段2.1逻辑计划解析2.2逻辑计划优化2.2.1Catalys的优化过程2.2.2CacheManager优化2物理优化阶段2.1优化SparkPlan2.1.1Catalyst的 Join策略2.1.2 如何决定选择哪一种Join策略2.2PhysicalPlan2.2.1EnsureRequirements规则Spar......
  • 最优化(11):信赖域算法、非线性最小问题二乘算法
    4.6信赖域算法——第一小节给出了信赖域算法的框架,第二小节讨论了信赖域子问题的求解方法(迭代法、截断共轭梯度法),第三小节主要介绍算法收敛性;4.7非线性最小二乘问题算法——第一小节给出了非线性最小二乘问题的一般形式,第二小节主要介绍高斯-牛顿算法,第三小节主要介绍Leve......