Java 在成本资源控制下, 千万级别数据查询优化
一.需求背景需求:分页列表的查询功能 , 按第三方业务系统数据已有的设计 , 根据用户和公司维度统计金额, 并且按项目维度进行数据权限的控制:
二.实现方式:根据需求要求根据用户和公司维度统计金额,涉及到 6 个业务表,分别是[订单明细,订单批次,用户,项目,合同,公司] ,1 个[订单明细]关联 1 个[用户]1 个[订单批次]关联 N 个[订单明细] ,1 个[订单批次]关联 1 个[项目] ,1 个[项目] 关联 1 个[合同],1 个[合同]关联 1 个[公司]
当时[订单明细]的数据量:开发环境:400 万生产环境:5700 万
数据库配置: 4 核 8G
1.实现方式一, 使用 GROUP BY:
已创建对应的索引
1.1.分页查询 sql:
1.2.总记录数查询 sql:
因在开发环境还没达到生产环境的数据量, 执行效率就已经这么慢, 是接受不了的,估想另外的实现方式
2.实现方式二:
使用汇总表, 避免 group by 语句和减少联表
但使用汇总表 ,会遇到几个问题,如 1.因业务方没有维护[更新时间]字段,估需定时任务每天统计汇总,就不是实时数据,是 N+12.数据权限维度的改变,不可采用项目维度进行控制, 需调整到公司维度控制
跟产品沟通后, 不能接受第 2 点数据权限的问题,故此方案 pass。
3.实现方式三:
新增扩展表, 把需要的外键 id 放在扩展表,减少联表
3.1.全量初始化扩展表定时任务(只执行一次)
3.2.新增 toll_order 的扩展表, 把身份证,项目 id,公司 id 等字段记录到扩展表, 避免联表,列表分页查询改用扩展表.
3.3.使用 DTS 订阅数据变化发送 MQ,通过接受 MQ 增量更新扩展表的数据,并把该订阅的数据存储至 重试表(用状态区分:处理完成, 处理失败)
3.4.重试定时任务: 查询处理失败的数据, 更新扩展表的数据, 更新重试表 (需保证同一 id 下的失败记录,按 MQ 时间戳升序排序,先处理第一个成功才执行后续的 , 否则执行顺序混乱会导致脏数据)
分页查询 sql:
总记录数查询 sql:
目前还是采用 Mybatis plus 的分页工具 , 开发环境与生产环境数据量差距较大, 还是存在潜在的性能问题:1.分页最后一页的查询: 开发环境耗时 20s2.总记录数的查询:开发环境耗时 20s
继续优化,方案如下:
分页查询:1.列表手动分页的查询语句调整,去除 group by 语句,改使用 distinct,然后再根据 cert_no,company_id 去 in 查询记录, 在代码层把 cert_no+company_id 作为 key 进行汇总金额, 分页 sql 如下:
总记录数:1.列表接口手动分页, 不执行 count()语句的查询 2.新增一个查询总记录数和页数的接口: 通过当前登录人查询缓存获取总记录数, 有筛选条件则查询数据库 3.登录的时候, 触发查询总记录数,存储至缓存(先判断是否有该菜单权限和数据权限, 没有则不查询), 总记录数的查询不使用 group by 语句, 改使用 distinct , sql 如下:
至此,在现有成本资源的控制下, 目前是最佳处理方式, 若还有更好的不增加成本的方案,欢迎给出建议
相关推荐
前端的世界总是在不断变化,作为开发者,我们需要保持好奇心和学习热情,不断探索新的技术,只有这样,我们才能在这个快速发展的时代中立于不败之地。低代码也是一个值得我们深入探索的领域,让我们拭目以待,它将给前端世界带来怎样的变革。
介绍一款程序员都应该知道的软件JNPF快速开发平台,很多人都尝试用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。
JNPF 可以实现应用从创建、配置、开发、测试到发布、运维、升级等完整生命周期的管理。减少了传统应用程序的代码编写量,通过图形化、可视化的界面,以拖放组件的方式,即可快速生成应用程序的产品,大幅降低了开发企业管理类软件的难度。
希望这篇文章对你有所帮助~
评论