深度解析:轨迹数据抽稀到底该放数据库还是 Java?(以 56800 条数据为例)

在低空飞服项目开发中,轨迹数据量通常非常大,一个飞行器一次飞行就可能产生数万条轨迹点。如果直接返回给前端,地图渲染会卡顿,因此必须做 抽稀(down sampling)

很多同学第一反应是:在 SQL 中抽稀

例如经典写法:

复制代码
SELECT *
FROM (
   SELECT t.*, ROW_NUMBER() OVER(ORDER BY update_time) AS rn
   FROM th_track t
   WHERE callsign = #{callsign}
) tmp
WHERE rn % 10 = 0
ORDER BY update_time

看上去减少了返回数据量,但实际是否真的减少了数据库压力?

查询真的会更快吗?

本文以实际项目中的 56800 条轨迹数据规模 进行分析。


❗ 结论先行:这种 SQL 抽稀方式不会减少数据库查询耗时

原因很简单:

数据库仍然必须执行:

  1. 全表扫描(56800 行)

  2. ORDER BY 排序(消耗 CPU)

  3. ROW_NUMBER() 窗口函数计算(消耗更多 CPU)

  4. 最后才过滤掉 90% 的数据

也就是说:

你只减少了前端接收的数据量,但数据库的工作量反而变大了。

特别是在 DM8 / DM7 上,窗口函数性能并不算强,这类 SQL 抽稀往往比简单查询更慢。


📊 56800 行轨迹数据的规模分析

轨迹表 th_track 一般包含:

  • 经纬度

  • 高度

  • 航向

  • 速度

  • UAV 状态

  • JSON 信号包

  • 扩展字段

如果 SELECT *,每条记录约 0.3KB~1.2KB。

56800 条数据约:

约 20MB ~ 60MB I/O 扫描量

这种 I/O 才是数据库最耗时的部分,

抽稀并不能减少这部分的消耗。


🚀 那应该怎么优化?

为了提升整体性能,我们必须明确目标:

层级 目标
数据库 尽可能减少扫描和排序
后端 控制前端数据量
前端 不卡顿、不掉帧

下面是几个行之有效的优化方案。


⭐ 方案 1:抽秒式 SQL 抽稀(数据库真正减少扫描量)【推荐】

如果 update_time 较规律(精确到秒),

可以用"按秒取样"代替窗口函数:

复制代码
SELECT id, lon, lat, altitude, update_time
FROM th_track
WHERE callsign = #{callsign}
  AND MOD(EXTRACT(SECOND FROM update_time), 10) = 0
ORDER BY update_time

优势:

  • 不需要排序

  • 不需要窗口函数

  • 扫描量明显减少

  • DM 数据库执行极快

这是 DM 的最佳实践之一。


⭐ 方案 2:只查询必要字段(最有效)

替换 SELECT *:

复制代码
SELECT id, lon, lat, altitude, speed, update_time
FROM th_track
WHERE callsign = #{callsign}
ORDER BY update_time

好处:

数据从 60MB → 10MB

DB I/O 直接降低 3~8 倍

这是所有优化中 影响最大 的。


⭐ 方案 3:Java 层抽稀(最稳健,推荐给 DM)

数据库只管查,不管抽稀:

复制代码
if (list.size() > 20000) {
    List<Track> slim = new ArrayList<>();
    for (int i = 0; i < list.size(); i += interval) {
        slim.add(list.get(i));
    }
    list = slim;
}

特点:

  • 不给数据库增加额外负担

  • 控制逻辑更灵活

  • 性能受 JVM 控制,易评估

  • 前端数据量仍然可控

对于 56800 条数据,Java 抽稀耗时只有 1~3ms


⭐ 方案 4:SQL + FETCH 限流(保障数据库不炸)

复制代码
SELECT t.*, ROW_NUMBER() OVER(ORDER BY update_time) AS rn
FROM th_track t
WHERE callsign = #{callsign}
FETCH FIRST 20000 ROWS ONLY

效果:

  • 限制最大扫描行数

  • 防止异常轨迹量导致数据库卡顿

不过仍然属于"治标不治本"。


🔥 最佳策略(推荐优先级)

① 数据库减负 > ② 后端控制 > ③ 前端不卡

最终最佳组合:

✔ 1. 不用窗口函数抽稀

(对 DM 性能不友好)

✔ 2. 不用 SELECT *

(避免大量字段 I/O)

✔ 3. 使用"按秒抽稀"或 Java 抽稀

(稳定、高效、无副作用)

✔ 4. back-end 抽稀控制最终返回数据量

(例如不超过 5000 点)


🎯 最后总结(非常重要)

方式 是否减轻 DB 压力 是否减少前端数据 是否推荐
窗口函数 SQL 抽稀 ❌ 否,反而更慢 ✔ 是 ⚠️ 不推荐
按秒抽稀 SQL ✔ 大幅降低 ✔ 是 ⭐ 强烈推荐
Java 抽稀 ✔ 不增加 DB 负担 ✔ 是 ⭐ 强烈推荐
LIMIT 限流 ✔ 避免爆表 ➖ 一般 可选
相关推荐
m0_561359672 小时前
使用Docker容器化你的Python应用
jvm·数据库·python
一条闲鱼_mytube2 小时前
MySQL vs PostgreSQL 对比
数据库·mysql·postgresql
Maynor9962 小时前
Clawdbot安装教程:从零开始到接入飞书
java·数据库·飞书
小北方城市网2 小时前
Spring Boot 多数据源与事务管理实战:主从分离、动态切换与事务一致性
java·开发语言·jvm·数据库·mysql·oracle·mybatis
痴儿哈哈2 小时前
C++与硬件交互编程
开发语言·c++·算法
roman_日积跬步-终至千里3 小时前
【Java 并发-面试】从线程基础到企业级开发的知识点概况
java·开发语言
云中飞鸿3 小时前
VS2015安装后,安装QT59,之后安装qt-vsaddin-msvc2015-2.4.3.vsix 文件失败问题!
开发语言·qt
m0_748233173 小时前
C与C++:底层编程的六大核心共性
java·开发语言
u0109272713 小时前
使用Scrapy框架构建分布式爬虫
jvm·数据库·python
沐知全栈开发3 小时前
HTTP Content-Type
开发语言