TDengine 新功能 复合主键
1. 简介
从 TDengine 3.3.0.0 版本之后,新增了复合主键的功能。
TDengine 原来的时间列是不允许有重复时间戳的,有了复合主键功能后,时间列即允许有重复,重复后的时间戳按紧跟其后第二列主键列的值来确定唯一性。
此功能的常用场景如高速收费口,同一时间内可能会多辆车通过,股票交易记录,同一时间内笔成交等多种实际应用场景。
2. 功能说明
2.1 建表
用户可以在建表时用 PRIMARY KEY
关键字,额外指定除主键时间戳列以外的另一列作为主键列,该列与时间戳列共同组成一行数据的键值,其类型必须为整型(int32, int64, uint32, uint64) 或 字符串类型(varchar)。超级表与普通表均支持复合主键。复合主键列不支持修改、增加和删除操作。PRIMARY KEY 列只能设置为第二列。
具体 SQL 语句如下:
CREATE TABLE t ( ts TIMESTAMP, obj_id VARCHAR(64) PRIMARY KEY, data1 FLOAT, data2 int );
2.2 写入
只有当时间戳相同且 PRIAMRY KEY 列值都相同时,两行数据才会被认为是重复数据,否则被认为是两行不同数据。如果时间戳相同但 Primary key 较小数据后写入,则视为乱序数据处理。
schemaless 写入不支持复合主键的情况,因为 schemaless 本身就是没有 schema,没法确定复合主键,目前的三种 schemaless 协议 (influxdb line/opentsdb telnet/opentsdb json) 也没有复合主键这个概念。
2.3 删除
删除操作与现有删除操作一样,只支持按时间段删除,不支持按主键范围删除。
2.4 查询
2.4.1 数据读取
查询复合主键数据时,时间戳相同且 PRIMARY KEY 列值相同时,被认为是一行数据。对于复合主键(时间戳+PRIMARY KEY 列)相同但被多次写入的重复数据则在合并更新后返回。只有复合主键不同的行被认为不同的行数据,被查询分别返回。每个表的读取结果是按(时间戳主键,Primary Key)有序。其他查询行为也将相应地变动。具体变化内容见后续章节。
查询行为的适配源自于TSDB reader 返回给上层的基础数据结构 SSDataBlock中包含了时间戳相同,但primary key 不同的记录。
2.4.2 标量查询
此原来行为相同,无改变
2.4.3 聚合查询
- 非时间窗口类:用户可见层面无变化。
- 时间窗口聚合类:TDengine 系统中针对时间窗口采用闭区间进行描述,并且相同时间戳不同primary key的记录归属于同一个时间窗口。故用户可见的时间窗口无变化。
- 在超级表的查询中,已经有归属于不同时间线的相同时间戳的查询,增加了 primary key 以后,用户可见表现层面无任何变化。
2.4.4 查询函数
类别 | 函数名 | 是否变化 |
数据函数 | ABS | 无影响 |
ACOS | 无影响 | |
ASIN | 无影响 | |
ATAN | 无影响 | |
CEIL | 无影响 | |
COS | 无影响 | |
FLOOR | 无影响 | |
LOG | 无影响 | |
POW | 无影响 | |
ROUND | 无影响 | |
SIN | 无影响 | |
SQRT | 无影响 | |
TAN | 无影响 | |
字符串函数 | CHAR_LENGTH | 无影响 |
CONCAT | 无影响 | |
CONCAT_WS | 无影响 | |
LENGTH | 无影响 | |
LOWER | 无影响 | |
LTRIM | 无影响 | |
RTRIM | 无影响 | |
SUBSTR | 无影响 | |
UPPER | 无影响 | |
时间和日期函数 | TIMEDIFF | 无影响 |
TIMETRUNCATE | 无影响 | |
转换函数 | CAST | 无影响 |
TO_ISO8601 | 无影响 | |
TO_JSON | 无影响 | |
TO_UNIXTIMESTAMP | 无影响 | |
TO_CHAR | 无影响 | |
TO_TIMESTAMP | 无影响 | |
聚合函数 | APERCENTILE | 无影响 |
AVG | 无影响 | |
COUNT | 无影响 | |
ELAPSED | 无影响 | |
LEASTSQUARES | 无影响 | |
SPREAD | 无影响 | |
STDDEV | 无影响 | |
SUM | 无影响 | |
HYPERLOGLOG | 无影响 | |
HISTOGRAM | 无影响 | |
PERCENTILE | 无影响 | |
选择函数 | BOTTOM | 无影响 |
FIRST | 有变化 | |
INTERP | 有变化 | |
LAST | 有变化 | |
LAST_ROW | 有变化 | |
MAX | 无影响 | |
MIN | 无影响 | |
MODE | 无影响 | |
SAMPLE | 无影响 | |
TAIL | 无影响 | |
TOP | 无影响 | |
UNIQUE | 有变化 | |
时序数据特有函数 | CSUM | 无影响 |
DERIVATIVE | 有变化 | |
DIFF | 有变化 | |
IRATE | 有变化 | |
MAVG | 无影响 | |
STATECOUNT | 无影响 | |
STATEDURATION | 无影响 | |
TWA | 有变化 |
变化的函数行为变化如下:
1. Interp
Interp 函数返回设定时间点 T 0 的插值(断面)数据,其前置时间戳 Tprev(小于 T0的最大时间戳)或后置时间戳Tnxt(大于T0的最小时间戳)可能有重复时间,并且其对应的数值不同。
进行插值计算时,前置时间戳 Tprev 或后置时间戳 Tnxt 均只使用首次出现的记录进行计算,丢弃其后出现的相同时间戳不同主键的记录。
首次出现的定义:对于任一时间戳Tx,在按照升序返回的数据记录中,(同一个表中数据)第一条 Tx 的记录即为首次出现记录。降序返回的数据记录中(同一个表中数据)Tx 最后一次出现的记录为首次出现。
需要注意,首次出现的判定只针对同一个表,对于超级表下的不同的表,无首次出现的判定。
2. FIRST
First 返回时间戳最小的记录。对于同一个表中具有相同(最小)时间戳不同主键的情况,返回该表中具有该时间戳的所有记录中首次出现的记录。
首次出现定义同上。
超级表查询中,在完成上述逻辑以后,还需要对来自不同表的时间戳进行比较和取舍,针对来自不同vnode的记录,如果 ts 相同需要进行 primary key 的比较。因此 first 函数返回的全局最小的(ts + primary key) 最早的结果。
3. LAST
Last 返回时间戳最大的记录。对于同一个表中具有相同(最大)时间戳不同主键的情况,返回该表中具有该时间戳的所有记录中末次出现的记录。
末次出现定义对应于首次出现的定义。
针对超级表跨 vnode 查询返回的结果,其判定逻辑于 FIRST 函数处理逻辑相同,需要同时比较 ts + primary key
4. LAST_ROW
与 last 函数相同。
5. UNIQUE
Unique 返回任一时间戳第一次出现的记录。对于同一个表中的记录,只返回首次出现的记录。不同子表中的相同时间戳记录,判定逻辑不变。
首次出现定义同上。
6. DERIVATIVE
同一个子表中的记录,使用首次出现记录进行计算,忽略后续出现的相同时间戳不同主键的记录。
首次出现定义同上。
7. DIFF
同一个子表中的记录,使用首次出现记录进行计算,忽略后续出现的相同时间戳不同主键的记录。
首次出现定义同上。
8. IRATE
同 derivative 函数处理逻辑相同。
9. TWA
同一个子表中数据进行窗口边界插值的时候,均使用首次出现记录进行插值计算返回结果。非首次出现记录不参与计算。
首次出现定义同上。
10. show create
Show create
返回创建(超级)表的SQL 语句,对于有 primary key 的(超级)表,相应的 SQL 语句有变化
11. DESC <table_name>
DESC 获取 (超级)表的 schema 信息,返回的结果中,需要标记第二列(primary key 只能为第二列)是否是 primary key 列。
12. INSERT INTO <table_name> SELECT
会进行符合性检查,具有 primary key 的(超级)表的不能向无 primary key 的表中写入数据。无 primary key 的表可以向具有 primary key 的表写入数据。
向 primary key 的表写入数据的时候,要求 primary key 列必须非 NULL。
2.4.5 查询子句
序号 | 子句 | 行为变化 |
1 | 比较表达式/条件子句 | 无影响 |
2 | fill 子句 | 无影响 |
3 | 窗口子句 | 无影响 |
4 | group by 子句 | 无影响 |
5 | partition by 子句 | 无影响 |
6 | join 查询 | 无影响 |
7 | Distinct 子句 | 无影响 |
8 | union子句 | 无影响 |
9 | slimit子句 | 无影响 |
10 | limit子句 | 无影响 |
11 | order by子句 | 无影响 |
12 | having子句 | 无影响 |
13 | range子句 | 无影响 |
14 | every子句 | 无影响 |
15 | 子查询 | 无影响 |
2.5 流计算
2.5.1 流计算窗口
对我们所支持的窗口类型,即 Interval、Session窗口,如果数据源表是复合主键,数据先按时间戳排序,时间戳相同的,再按复合主键排序,然后才是其他列排序。所以复合主键场景,流计算当前的设计和实现能够透明处理,符合流计算窗口当前的预期。存储流计算结果的表是复合主键,则Interval、Session 窗口输出结果时,需要按照时间戳和复合主键排序。
流计算对于乱序数据的界定方式:当前这批写入的数据,与之前写入的数据做对比。窗口计算要求数据按时间戳有序,只是要求当前这批数据,这个是局部的,并不是要求数据源的全部数据有序。
2.5.2 创建流计算
需要考虑存储流计算结果的表。对于自动创建超级表场景,需要提供复合主键的信息。新增语法,在创建流计算的SQL中,显式指定复合主键信息,即流计算结果中,哪些列是复合主键。对于写入已存在超级表,通过元数据能够获取复合主键的信息,不需要SQL中指定。
语法如下:
CREATE STREAM [IF NOT EXISTS] stream_name [stream_options] INTO stb_name[(field1_name, field2_name [PRIMARY KEY], field3_name, ...)] [TAGS (create_definition [, create_definition] ...)] SUBTABLE(expression) AS subquery
PRIMARY KEY 使用规则和限制与建表SQL相同。
2.5.3 流计算中不支持的场景
由于需要按照 PK 删除 已经生成的记录。因此,不支持状态窗口、事件窗口、计数窗口在有 pk 的表上进行计算。对于全是标量函数的流计算,不支持数据源是复合主键,且目标表不是复合主键。
2.6 订阅
2.6.1 接口变更
-
tmq_get_json_meta(获取meta信息的 json 描述)
该接口内部创建表数据结构里增加列是否是复合主键参数("isPrimarykey":true)。已在文档里更新: https://jira.taosdata.com:18090/pages/viewpage.action?pageId=158206215
-
tmq_get_raw 接口返回的 raw data 做了升级,请查看文档 数据订阅结果序列化方案
2.6.2 其它接口无变更
2.7 Last 缓存
-
cache_model: none,返回最大的时间戳和该时间戳下最大的主键所对应的行或值
-
cache_mode: last_value, last_row, both,查询行为受缓存更新规则影响,更新规则如下:
缓存的更新粒度仍然是表级别。在主时间戳列相同情况下,主键列按大小顺序取最大值。即在更新缓存时,新到达的数据与当前 last 缓存中的数据相比,如果时间戳更大或时间戳相同但主键值更大则更新缓存,否则不更新缓存。
3. 性能影响
3.1 写入性能
-
非重复时间戳:在没有任何两条记录时间戳相同的情况下,其写入性能与未引入 primary key 相比完全相同
-
有重复时间戳的场景:在极端情况下,时间戳全部相同,而 primary key 单调递增,预估这种场景下写入性能下降 50%,原因是要进行两次键值比较。
-
纯乱序数据写入:即任意一行记录的时间戳和 primary key 都有可能小于之前已经写入的部分记录,这种情况下仍旧无法预估性能下降的比例。原则乱序程度越高,性能下降越明显
3.2 查询性能
3.2.1 数据读取
读取过程中,在merge阶段需要同时比较 ts 和 primary key column,因此 merge 过程会消耗更多的 CPU,记录合并过程会出现明显地性能下降。
合并过程是在 tsdb 完成,因此所有的查询均受影响(只使用 head 文件 和 SMA 索引的查询除外)。性能受到的影响程度受 key长度、数据写入模式、数据在文件中物理分布、数据重复比例、数据读取开销在整个查询过程中资源开销占比等诸多因素共同影响,无法简单评估性能下降的程度。
3.2.2 不同类型查询性能表现
在排除数据读取性能降低的场景下,对于非分组类型的查询(没有 partition by 和 group by 子句),没有明显的变化。
4. 兼容性
1. 不会对已存在的数据产生影响,数据不支持版本回退,因为低版本识别不出复合主键。
2. 流计算会有影响。需要删除删除流计算才能进行升级。
5. 约束和限制
-
只允许额外指定除时间戳以外的一列作为主键
-
支持定长和变长类数据类型,暂定支持非浮点数及 varchar。
-
主键与时间戳列一样,不允许缺省或为 NULL
-
主键列不允许 alter 或 drop 等操作
-
已建无主键列的表不可以通过 alter 语句添加主键列
-
不支持对主键列的范围删除
6. 总结
本章主要介绍了新功能复合主键的对外接口使用、影响的功能及函数内部技术实现,受约条件等,帮助技术开发人员更好了解及使用此功能。
相关文章:
TDengine 新功能 复合主键
1. 简介 从 TDengine 3.3.0.0 版本之后,新增了复合主键的功能。 TDengine 原来的时间列是不允许有重复时间戳的,有了复合主键功能后,时间列即允许有重复,重复后的时间戳按紧跟其后第二列主键列的值来确定唯一性。 此功能的常用…...
JVM 面试题
Java 虚拟机(JVM)是运行 Java 程序的引擎,它是 Java 语言 “一次编译,处处运行” 的核心技术。JVM 的主要任务是将 Java 字节码(Bytecode)解释成机器码并执行,负责内存管理、线程管理、垃圾回收…...
组件上传图片不回显问题
import { Plus } from "element-plus/icons-vue"; // 图片上传 const img_add ref([]); function httpRequest_add(option) {let dataForm new FormData();dataForm.append("file", option.file);dataForm.append("id", user.data.id);axios({…...
【JavaWeb后端学习笔记】Spring AOP面向切面编程
AOP 1、Spring AOP概述2、SpringAOP快速入门3、SpringAOP核心概念4、通知类型5、通知顺序6、切入点表达式6.1 execution方式6.2 annotation方式 7、连接点 1、Spring AOP概述 AOP:Aspect Oriented Programming,面向特定方法编程。 AOP是通过动态代理技术…...

6.584-Lab5B
6.584-Lab5B Reference CodeReference BlogHomeworkMyself Code Sharded Key/Value Service 梗概 这个图是我从上面参考blog中拿来的,觉得做的不错,借助这张图来讲解一下需要一个什么样的 Service。 ShardCtrler Client: 接收来自客户发出的命…...

OceanBase 的探索与实践
作者:来自 vivo 互联网数据库团队- Xu Shaohui 本文总结了目前我们遇到的痛点问题并通过 OceanBase 的技术方案解决了这些痛点问题,完整的描述了 OceanBase 的实施落地,通过迁移到 OceanBase 实践案例中遇到的问题与解决方案让大家能更好的了…...

安卓调试环境搭建
前言 前段时间电脑重装了系统,最近准备调试一个apk,没想到装环境的过程并不顺利,很让人火大,于是记录一下。 反编译工具下载 下载apktool.bat和apktool.jar 官网地址:https://ibotpeaches.github.io/Apktool/install…...
动画Lottie
Lottie简介 Lottie是一个Airbnb 开发的用于Android,iOS,Web和Windows的库,用于解析使用Bodymovin导出为json的Adobe After Effects动画,并在移动设备和网络上呈现 — GitHub Lottie主要特性 After Effects 兼容性: …...

C++感受14-Hello Object 封装版 - 上
1. 封装即约束——封装和派生、多态的本质区别 一门计算机语言,要如何帮助程序员写出优秀的代码?两个方法:一是给程序员更多能力,二是给程序员更多约束。之前我们学习的派生和多态,更多的是给我们技能,而封…...

网络安全中大数据和人工智能应用实践
传统的网络安全防护手段主要是通过单点的网络安全设备,随着网络攻击的方式和手段不断的变化,大数据和人工智能技术也在最近十年飞速地发展,网络安全防护也逐渐开始拥抱大数据和人工智能。传统的安全设备和防护手段容易形成数据孤岛࿰…...
RISC-V架构下OP-TEE 安全系统实践
安全之安全(security)博客目录导读 本篇博客,我们聚焦RISC-V 2024中国峰会上的RISC-V和OP-TEE结合的一个安全系统实践,来自芯来科技桂兵老师。 关于RISC-V TEE(可信执行环境)的相关方案,如感兴趣可参考R...

40分钟学 Go 语言高并发:【实战】分布式缓存系统
【实战课程】分布式缓存系统 一、整体架构设计 首先,让我们通过架构图了解分布式缓存系统的整体设计: 核心组件 组件名称功能描述技术选型负载均衡层请求分发、节点选择一致性哈希缓存节点数据存储、过期处理内存存储 持久化同步机制节点间数据同步…...
[创业之路-186]:《华为战略管理法-DSTE实战体系》-1-为什么UTStarcom死了,华为却活了,而且越活越好?
目录 前言 一、市场定位与战略选择 二、技术创新能力 三、企业文化与团队建设 四、应对危机的能力 五、客户为中心的理念 六、市场适应性与战略灵活性 七、技术创新与研发投入 八、企业文化与团队建设 九、应对危机的能力 前言 UT斯达康(UTStarcom&#…...
python如何多行注释
在Python中,多行注释通常有两种方式: 使用三个单引号()或三个双引号(""")来创建多行字符串,这可以被用来作为多行注释。这种方式在Python中实际上是创建了一个多行的字符串对象…...
前端工程化面试题目常见
前端工程化面试常见题目包括: • 谈谈你对WebPack的认识。 • Webpack打包的流程是什么? • 说说你工作中几个常用的loader。 • 说说HtmlWebpackPlugin插件的作用。 • Webpack支持的脚本模块规范有哪些? • Webpack和gulp/grunt相比有什么特…...

定点数的乘除运算
原码一位乘法 乘积的符号由两个数的符号位异或而成。(不参与运算)被乘数和乘数均取绝对值参与运算,看作无符号数。乘数的最低位为Yn: 若Yn1,则部分积加上被乘数|x|,然后逻辑右移一位;若Yn0&…...

页面置换算法模拟 最近最久未使用(LRU)算法
最近最久未使用(LRU)算法是一种基于页面访问历史的页面置换算法。它选择最久未使用的页面进行置换。当需要访问一个不在内存中的页面时,如果内存已满,则选择最久未使用的页面进行置换。LRU算法通过记录页面的访问时间戳来判断页面…...
Ubuntu与Centos系统有何区别?
Ubuntu和CentOS都是基于Linux内核的操作系统,但它们在设计理念、使用场景和技术实现上有显著的区别。以下是详细的对比: 1. 基础和发行版本 Ubuntu: 基于Debian,使用.deb包管理系统。包含两个主要版本: LTSÿ…...

RK3568平台开发系列讲解(pinctrl 子系统篇)pinctrl_debug
🚀返回专栏总目录 文章目录 1. Overview2. debug信息2.1 pinctrl-devices2.2. pinctrl-handles2.3. pinctrl-handles3. debug信息3.1. 查看(pinctrl_register_pins)注册了哪些pins3.2. 查看pin groups;3.3. 查看每种functions所占用的gpio groups信息:3.4. pinconf沉淀、…...
避大坑!Vue3中reactive丢失响应式的问题
在vue3中,我们定义响应式数据无非是ref和reactive。 但是有的小伙伴会踩雷!导致定义的响应式丢失的问题。 reactive丢失响应式的情况1(直接赋值) 场景: 1.你定义了一个数据:let datareactive({name:"",age:"" }) 2.然后你…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...

Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...