Spring Boot 中 PGSQL 判断打卡点是否经过轨迹优化代码,循环查询物理表修改生成临时表,向临时表插入数据后再做ST_DWithin判断

news2025/1/11 11:40:46

记录一下一个业务问题,流程是这样的,我现在有一个定时任务,5分钟执行一次,更新车辆打卡的情况。现在有20俩车,每辆车都分配了路线,每条路线都有打卡点,每个打卡点分配了不同的时间段,也就是说,一条路线可能有几百个打卡点,这几百个打卡点中每一个都分配了时间段,有可能是1个时间段,比如8:00 - 10:00这个时间段,要去打卡。也有可能有的打卡点分配了几个时间段,比如上午两个时间段,下午两个时间段。这个时候要去判断今天的打卡情况,只能先获取路线的打卡点,然后再获取单个打卡点下面的时间段,再进行判断操作。但是问题来了,之前的写法for循环去判断只针对少数打卡点,比如一条路线也就5 - 10个打卡点这样。但是现在打卡点数量过多,路线增加,以及每个打卡点都有打卡时间段,for循环操作数据库判断无比的慢,以及非常的消耗资源内存等。。但是判断是否经过打卡点这种必须要在sql里面执行判断,之所有必须在sql判断,因为pgsql提供的ST_DWithin函数就是判断是否在缓冲区范围经过打卡点的。。所以离不开sql判断。下面代码是for循环的操作,先循环出单条路线的打卡点,然后再根据打卡点的ID用stream流匹配打卡点的时间段,再循环每个时间段到sql里面进行判断。

在这里插入图片描述

sql语句判断是这样的

在这里插入图片描述

既然我们离不开sql语句判断,那就只能按照老套路,加索引这些。但是加索引提升了一点查询速度,持续的查询非常的消耗内存,导致项目运行的时候内存持续的猛增。一天时间涨了2G多,这明显很离谱。。。即使GC了,内存也无法得到释放。

在这里插入图片描述

咨询了部门里的老大哥,我问他我这种打卡点判断,能不能不走sql,他说不行的,这种必须走sql的,必须走pg的ST_DWithin函数判断。他给了我一个解决方案,让我先获取出当天的轨迹数据,也就是car_trajectory_info物理表的当天数据,每次定时任务执行的时候,先查出当天的轨迹数据,然后创建临时表,把当天的轨迹数据放到临时表里面,然后把之前的sql判断语句只查临时表,比如创建了一个临时表car_trajectory_info_temp,把原来的sql语句的物理表car_trajectory_info改成car_trajectory_info_temp,执行判断结束后在把临时表删除掉。这样下来,就不会走物理表了,直接走临时表做查询(这里记得在创建临时表的时候加上索引)

具体实现临时表操作如下:

测试类

package com.yutu.garden.task;

import cn.hutool.core.collection.CollUtil;
import com.yutu.garden.entity.CarTrajectoryInfo;
import com.yutu.garden.mapper.gardens.CarTrajectoryInfoMapper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Component
@EnableScheduling
public class ScheduledTasks01 {

	@Resource
	private CarTrajectoryInfoMapper carTrajectoryInfoMapper;

    // 第一个定时任务,每隔5秒执行一次
    @Async("taskExecutor")
    @Scheduled(cron = "*/10 * * * * *")
    @Transactional
    public void task() {

		//先查询出当天的轨迹数据,按照条件吧,如果还有条件,可以更加详细到某些指定的数据,比如说按车牌号条件筛选
		List<CarTrajectoryInfo> carTrajectoryInfoList = carTrajectoryInfoMapper.getToDayCarInfoList();

		//测试 创建临时表
		carTrajectoryInfoMapper.createTempTable();
		System.out.println("临时表创建成功");

		//递归向临时表中插入当天的数据(防止数据量过大引发IO异常)
		add(carTrajectoryInfoList,0L,500L);

        //查询临时表(在这里判断是否经过打卡点!)
        CarTrajectoryInfo carTrajectoryInfo = carTrajectoryInfoMapper.selectTempTable(必要的参数,这里只是测试);
		System.out.println("执行查询,如果为空,那就是没有经过打卡点,如果不为空那就是已经经过打卡点");
        System.out.println(carTrajectoryInfo);

		System.out.println("删除临时表");
		carTrajectoryInfoMapper.dropTempTable();

    }


	//递归插入(防止数据量过大引发IO异常)
	public void add (List<CarTrajectoryInfo> all,long start,long limit){
		//截取 从start开始截取 截取limit条
		List<CarTrajectoryInfo> collect = all.stream().skip(start).limit(limit).collect(Collectors.toList());
		if(CollUtil.isEmpty(collect)){
			return;
		}
		//批量插入数据的方法
		//保存车辆轨迹数据
		carTrajectoryInfoMapper.insertDataTempTable(collect);
		//递归 每次插入limit条数据
		add(all,start+limit,limit);
	}

}

mapper层

package com.yutu.garden.mapper.gardens;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yutu.garden.entity.CarTrajectoryInfo;
import com.yutu.garden.vo.CarWarnInfoCqZtVo;
import com.yutu.garden.vo.CarWarnInfoZyInfoVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.time.LocalDate;
import java.util.Date;
import java.util.List;


@Mapper
public interface CarTrajectoryInfoMapper extends BaseMapper<CarTrajectoryInfo> {

	//获取当天轨迹数据
	List<CarTrajectoryInfo> getToDayCarInfoList();

	//批量插入数据
	void insertDataTempTable(@Param("carTrajectoryInfoList") List<CarTrajectoryInfo> carTrajectoryInfoList);

	//创建临时表
	void createTempTable();

	//使用临时表执行判断
	CarTrajectoryInfo selectTempTable(@Param("geom")String geom,
									  @Param("sRid")Integer sRid,
									  @Param("carNo")String carNo,
									  @Param("radius") Integer radius,
									  @Param("startTime") String startTime,
									  @Param("endTime") String endTime);

	//删除临时表
	void dropTempTable();

}

xml中sql语句

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yutu.garden.mapper.gardens.CarTrajectoryInfoMapper">


    <select id="getToDayCarInfoList" resultType="com.yutu.garden.entity.CarTrajectoryInfo">
        select * from car_trajectory_info where DATE(upload_time) = CURRENT_DATE
    </select>


    <sql id="createTempTableSQL">
        CREATE TEMPORARY TABLE car_trajectory_info_temp (
          id int8 NOT NULL,
          car_no varchar(255),
          device_no varchar(255),
          lng float8,
          lat float8,
          speed float8,
          upload_time timestamp(6),
          distance float8,
          duration float8,
          today_distance float8,
          geom geometry,
          clean_area float8
        );
        CREATE INDEX car_trajectory_info_temp_car_no_idx ON car_trajectory_info_temp USING btree (car_no);
        CREATE UNIQUE INDEX car_trajectory_info_temp_id_uindex ON car_trajectory_info_temp USING btree (id);
        CREATE INDEX car_trajectory_info_temp_upload_time_idx ON car_trajectory_info_temp USING btree (upload_time);
        CREATE INDEX car_trajectory_info_temp_geom_idx ON car_trajectory_info_temp USING gist (geom);
    </sql>

    <update id="createTempTable">
        <include refid="createTempTableSQL"/>
    </update>

    <insert id="insertDataTempTable">
        INSERT INTO car_trajectory_info_temp
        (id,car_no, device_no, lng, lat, speed, upload_time, distance, duration, today_distance, geom, clean_area)
        VALUES
        <foreach collection="carTrajectoryInfoList" item="item" separator=",">
            (
            #{item.id},
            #{item.carNo},
            #{item.deviceNo},
            #{item.lng},
            #{item.lat},
            #{item.speed},
            #{item.uploadTime},
            #{item.distance},
            #{item.duration},
            #{item.todayDistance},
            st_geomfromtext(st_astext(#{item.geom}), 4326),
            #{item.cleanArea}
            )
        </foreach>
    </insert>

    <select id="selectTempTable" resultType="com.yutu.garden.entity.CarTrajectoryInfo">
        select
        id,upload_time,car_no
        from
        car_trajectory_info_temp
        where
        0=0
        <if test="geom != null and geom != ''">
            and ST_DWithin(geom, st_geomfromtext(st_astext(#{geom}), #{sRid}), #{radius},false)
        </if>
        <if test="carNo != null and carNo != ''">
            and car_no = #{carNo}
        </if>
        <if test="startTime != null and startTime != ''">
            and to_char(upload_time, 'HH24:MI:SS') &gt;= #{startTime}
        </if>
        <if test="endTime != null and endTime != ''">
            and to_char(upload_time, 'HH24:MI:SS') &lt;= #{endTime}
        </if>
        limit 1
    </select>

    <sql id="dropTempTableSQL">
        DROP TABLE IF EXISTS car_trajectory_info_temp;
    </sql>
    <update id="dropTempTable">
        <include refid="dropTempTableSQL"/>
    </update>

</mapper>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1886826.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【动态规划 前缀和】2478. 完美分割的方案数

本文涉及知识点 划分型dp 动态规划汇总 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode 2478. 完美分割的方案数 给你一个字符串 s &#xff0c;每个字符是数字 ‘1’ 到 ‘9’ &#xff0c;再给你两个整数 k 和 minLength 。 如…

Redis---保证主从节点一致性问题 +与数据库数据保持一致性问题

保证主从节点一致性问题 Redis的同步方式默认是异步的&#xff0c;这种异步的同步方式导致了主从之间的数据存在一定的延迟&#xff0c;因此Redis默认是弱一致性的。 解决&#xff1a; 1.使用Redisson这样的工具&#xff0c;它提供了分布式锁的实现&#xff0c;确保在分布式环…

python自动化运维--DNS处理模块dnspython

1.dnspython介绍 dnspython是Pyhton实现的一个DNS工具包&#xff0c;他几乎支持所有的记录类型&#xff0c;可以用于查询、传输并动态更新ZONE信息&#xff0c;同事支持TSIG&#xff08;事物签名&#xff09;验证消息和EDNS0&#xff08;扩展DNS&#xff09;。在系统管理方面&a…

京东云备案流程图_云主机快速ICP备案_京东云服务器备案问题解答

京东云ICP备案流程&#xff0c;备案包括网站和APP备案&#xff0c;以及备案问题解答FAQ&#xff0c;阿腾云以京东云网站域名备案流程为例&#xff0c;先填写主办单位信息&#xff0c;选择网站备案或APP备案&#xff0c;申请授权码并验证&#xff0c;填写并上传主办单位详细信息…

老挝语翻译成简体中文推荐用什么翻译工具?《老挝语翻译通》App满足你所有翻译需求!

如果你正在找一款支持把老挝语翻译成中文&#xff0c;或者把中文翻译成老挝语的翻译工具&#xff0c;不得不推荐你使用《老挝语翻译通》App&#xff0c;您的随身老挝语翻译官&#xff0c;带您轻松跨越语言障碍。 功能亮点&#xff1a; 实时翻译&#xff1a;中文与老挝语的无缝…

论文阅读【时间序列】DSformer

论文阅读【时间序列】DSformer arxive: DSformer: A Double Sampling Transformer for Multivariate Time Series Long-term Prediction github: MTST 分类&#xff1a;多变量时间序列&#xff08;Multivariate time series&#xff09; 核心观点 多变量时间序列3个维度信息 …

一款十六进制编辑器,你的瑞士军刀!!【送源码】

软件介绍 ImHex是一款功能强大的十六进制编辑器&#xff0c;专为逆向工程师、程序员以及夜间工作的用户设计。它不仅提供了基础的二进制数据编辑功能&#xff0c;还集成了一系列高级特性&#xff0c;使其成为分析和修改二进制文件的理想工具。 功能特点 专为逆向工程、编程和夜…

Appium adb 获取appActivity

方法一&#xff08;最简单有效的方法&#xff09; 通过cmd命令&#xff0c;前提是先打开手机中你要获取包名的APP adb devices -l 获取连接设备详细信息 adb shell dumpsys activity | grep mFocusedActivity 有时获取到的不是真实的Activity 方法二 adb shell monkey -p …

K6 性能测试教程:入门介绍,环境搭建和编写第一个 K6 测试脚本

K6 性能测试教程&#xff1a;入门介绍&#xff0c;环境搭建和编写第一个 K6 测试脚本 这篇文章将带您进入 K6 性能测试的世界。博文内容涵盖了 K6 性能测试的入门知识、环境搭建步骤&#xff0c;以及如何编写您的第一个测试脚本。无论您是初学者还是有经验的性能测试专业人员&…

剪映 v5.5 Pro Vip解锁版:使用指南与注意事项

摘要&#xff1a;本文介绍了剪映Pro VIP解锁版的使用方法&#xff0c;包括安装、测试和使用VIP素材的步骤&#xff0c;以及如何避免误报和保持解锁状态的建议。 正文&#xff1a; 剪映Pro是一款广受欢迎的视频编辑软件&#xff0c;提供了丰富的视频编辑功能和大量高质量的素材…

Python基础001

Python输出语句 print输出字符串 print("中国四大名著&#xff1a;","西游记|","三国演义|","红楼梦|","水浒传") print(6) print(1 1)Python输入语句 input函数 input() input("我的名字是&#xff1a;") p…

javaSE期末练习题

文章目录 前言一、程序控制1.顺序结构问题描述解题思路题解 2.选择结构2.1 题1问题描述解题思路题解 2.1 题2问题描述解题思路题解 3.循环结构3.1 阶乘的求取问题描述解题思路题解 3.2 水仙花数问题描述解题思路题解 二、数组三、类与对象1.类与对象1.1圆类问题描述解题思路题解…

【ES】--Elasticsearch的Nested类型介绍

目录 一、问题现象二、普通数组类型1、为什么普通数组类型匹配不准?三、nested类型四、nested类型查询操作1、只根据nested对象内部数组条件查询2、只根据nested对象外部条件查询3、根据nested对象内部及外部条件查询4、向nested对象数组追加新数据5、删除nested对象数组某一个…

【QT】常用控件|widget|QPushButton|RadioButton|核心属性

目录 ​编辑 概念 信号与槽机制 控件的多样性和定制性 核心属性 enabled geometry ​编辑 windowTiltle windowIcon toolTip styleSheet PushButton RadioButton 概念 QT 控件是构成图形用户界面&#xff08;GUI&#xff09;的基础组件&#xff0c;它们是实现与…

第十四届蓝桥杯省赛C++B组E题【接龙数列】题解(AC)

需求分析 题目要求最少删掉多少个数后&#xff0c;使得数列变为接龙数列。 相当于题目要求求出数组中的最长接龙子序列。 题目分析 对于一个数能不能放到接龙数列中&#xff0c;只关系到这个数的第一位和最后一位&#xff0c;所以我们可以先对数组进行预处理&#xff0c;将…

VMware创建新虚拟机教程(保姆级别)

&#x1f4e2; 续上一篇 最新超详细VMware虚拟机安装完整教程-CSDN博客 &#xff0c;本章将详细讲解VMware创建虚拟机。 一、创建新的虚拟机 点击【创建新的虚拟机】&#xff01; 点击【自定义&#xff08;高级&#xff09;】> 下一步&#xff01; > 默认下一步&#x…

[hive] posexplode生成从去年一月一号,到本月的月时间表

生成从去年一月一号&#xff0c;到本月的月时间表 posexplode用法&#xff1a; lateral view 表别名 as 序号列名,数组中的元素的名 1、生成序列 SELECT time_stamp_fist_day_of_last_year,--去年第一天的时间戳numfrom(SELECTsplit(repeat_o,,) o_array,time_stamp_fist_da…

【2024德国签证】去德国读博士需要申请什么签证?

德国留学签证面签的经过及注意事项 ✨&#xff01;希望我的经验可以帮助大家顺利通过签证&#xff0c;顺利开启德国留学之旅 。记得带上足够的现金和材料哦 &#xff01; 一、选择适合自己的签证类型 在选择签证类型时&#xff0c;一定要根据自己的实际情况来选择合适的签证种…

vmware虚拟机安装openEuler

一、openEuler简介 openEuler是一款开源操作系统。当前openEuler内核源于Linux&#xff0c;支持鲲鹏及其它多种处理器&#xff0c;能够充分释放计算芯片的潜能&#xff0c;是由全球开源贡献者构建的高效、稳定、安全的开源操作系统&#xff0c;适用于数据库、大数据、云计算、…

ESP32CAM物联网教学01

ESP32CAM物联网教学01 拍照 视频 这么小的一个开发板都带上摄像头了&#xff0c;能拍照&#xff1f;能视频吗&#xff1f;现在就跟着我做起来。 初识ESP32CAM 我们到淘宝搜索“ESP32Cam”&#xff0c;就能买到这样一块开发板。 ESP32Cam是双核处理器&#xff0c;提供WIFI和…