news 2026/9/6 5:11:07

Questdb 优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Questdb 优化

QuestDB LATEST ON / LATEST BY 查询十几秒慢,核心原因

几十亿行,LATEST ON timestamp PARTITION BY device_id,pname慢到十几秒,90% 都是下面 4 个坑QuestDB Co...

1、device_id /pname 没有设置成SYMBOL(头号元凶)

如果你的device_idpnameSTRING/VARCHAR而不是SYMBOLLATEST ON必须扫描全表,找出全部不重复设备,再反向扫描时间,几十亿数据直接十几秒。

✅正确建表:

sql

CREATE TABLE flow_meter_records ( timestamp TIMESTAMP, device_id SYMBOL CAPACITY 50000 CACHE, pname SYMBOL CAPACITY 200 CACHE, value DOUBLE ) TIMESTAMP(timestamp) PARTITION BY DAY WAL;
  • SYMBOL:重复多的字符串,内部字典编码,LATEST ON可以反向分区扫描,找到每个设备最新行立刻停止,毫秒级返回QuestDB Co...。
  • ❌不要用 STRING 做 PARTITION BY 字段。

⚠️已经建好的表不能直接改列类型,只能新建表迁移数据。

2、不要不带时间条件查全部历史分区

几十亿,几百个历史分区,LATEST ON会从最早分区开始扫。

优化:加一个大时间窗口 WHERE,告诉数据库不用扫描很早的旧分区

sql

SELECT * FROM flow_meter_records LATEST ON (timestamp) PARTITION BY device_id,pname WHERE timestamp > dateadd('d',‑90,now());

只扫描最近 90 天分区,跳过几年前冷分区,速度直接几倍提升。 业务上设备最新数据一定发生在最近几十天,很久没有上报的设备直接过滤掉。

3、Designated Timestamp 丢失

timestamp必须是表的TIMESTAMP()指定字段,不能套 cast 函数。套cast(timestamp as timestamp)会破坏分区裁剪,变成全扫描GitHub。

❌错误:

sql

LATEST ON (cast(timestamp as timestamp)) PARTITION BY device_id,pname

✅正确:

sql

LATEST ON (timestamp) PARTITION BY device_id,pname

4、老版本 QuestDB Bug

老版本LATEST ON高基数设备性能差,尽量升级到新版本。


两种业务方案(水务项目实际落地)

方案 A:查询所有设备最新值(用上面优化后的 SQL)

sql

SELECT * FROM flow_meter_records LATEST ON (timestamp) PARTITION BY device_id,pname WHERE timestamp > dateadd('d',‑90,now());

前提:device_id、pnameSYMBOL类型。

方案 B(强烈推荐,生产环境):维护一张最新值快照表

几十亿原始表永远不要频繁跑LATEST ON做接口查询!

  1. 定时任务(1 分钟 / 5 分钟)跑一次 LATEST ON,把每个设备最新结果写入一张小表flow_meter_latest
  2. Java 接口直接查询这张小快照表,毫秒返回,0 压力
  3. 原始大表只做历史查询、报表统计。

示例:

sql

-- 定时任务执行,覆盖更新最新状态 INSERT INTO flow_meter_latest SELECT * FROM flow_meter_records LATEST ON (timestamp) PARTITION BY device_id,pname WHERE timestamp > dateadd('d',‑90,now()) ON CONFLICT(device_id,pname) DO UPDATE;

接口直接查:

sql

SELECT * FROM flow_meter_latest where device_id = ?;

排查命令,看是不是扫描大量分区

sql

EXPLAIN SELECT * FROM flow_meter_records LATEST ON (timestamp) PARTITION BY device_id,pname WHERE timestamp > dateadd('d',‑90,now());

看输出,确认有partition pruning(分区裁剪生效)。

补充:查单个设备的最新一条

不要用 LATEST ON,直接排序取第一条:

sql

SELECT * FROM flow_meter_records WHERE device_id='DEV001' AND pname='累计流量' ORDER BY timestamp DESC LIMIT 1;

device_id 为 SYMBOL,这个查询会非常快。

总结

  1. device_idpname务必设置为SYMBOL,不要用 string;
  2. LATEST ON查询必须加时间条件,裁剪旧分区
  3. 高频接口不要直接查几十亿大表,维护一张小的最新快照表;
  4. designated timestamp 不要套 cast 函数。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 5:07:36

端侧AI语音机器人Microduck复刻指南:从硬件选型到模型微调

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 5:03:04

ARM体系结构学习路径:从Cortex-M到A系列的全景解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 5:02:44

Cmakelist进阶版

目标:不只是能够自己能用上自己写的库,让别人也能用。1.创建一个文件夹如下图所示,src存放库的.cpp文件,include存放库的.h文件,主程序是useHello.cpp2.往include和src里面放你的文件,并且编写你的主程序引用这个库。此…

作者头像 李华
网站建设 2026/9/6 5:00:34

鸿蒙App接入AI多轮对话:基于蓝耘MaaS的礼物推荐实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 5:00:02

基于Python和Vue3的学科竞赛管理系统毕业设计全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华