深度解析:轨迹数据抽稀到底该放数据库还是 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 限流 ✔ 避免爆表 ➖ 一般 可选
相关推荐
choke233几秒前
[特殊字符] Python异常处理
开发语言·python
云中飞鸿1 分钟前
linux中qt安装
开发语言·qt
少控科技15 分钟前
QT第6个程序 - 网页内容摘取
开发语言·qt
darkb1rd15 分钟前
八、PHP SAPI与运行环境差异
开发语言·网络安全·php·webshell
南极企鹅16 分钟前
springBoot项目有几个端口
java·spring boot·后端
历程里程碑18 分钟前
Linux20 : IO
linux·c语言·开发语言·数据结构·c++·算法
郝学胜-神的一滴20 分钟前
深入浅出:使用Linux系统函数构建高性能TCP服务器
linux·服务器·开发语言·网络·c++·tcp/ip·程序人生
清风拂山岗 明月照大江22 分钟前
Redis笔记汇总
java·redis·缓存
承渊政道23 分钟前
Linux系统学习【Linux系统的进度条实现、版本控制器git和调试器gdb介绍】
linux·开发语言·笔记·git·学习·gitee
未来之窗软件服务24 分钟前
计算机等级考试—高频英语词汇—东方仙盟练气期
数据库·计算机软考·东方仙盟