TDengine 重磅功能虚拟表
简介
虚拟表功能是 TDengine 最近刚发现的 3.3.6.0 版本中一项重磅级新功能,虚拟表可理解为在原来查询基础上做了一层逻辑表,在数据查询建模时即可不依赖底层物理存储表,直接通过虚拟表进行数据查询建模,这样逻辑上会更加清晰,同时在灵活性也非常高,随时可以拆了建模不合理的虚拟表再建,而物理存储表是不能这样拆了重建的。
TDengine 的虚拟表,真正实现了一个设备一张表的设计理念。虚拟表有如下特点:
- 数据建模:采集层常采用单列模型,应用层常采用宽表多列模型,IT 和 OT 间需要桥梁
- 标签维护:一个设备存在多张子表时,带来标签重复存储,多个子表的标签更新存在原子性问题
- 查询易用性:跨表查询需要编写的 JOIN 语句,常需要多次查询拼接
- 查询效率:按时间戳对齐跨表数据的效率低,查询延迟显著增加
- 查询维护:视图需定义固定的查询逻辑,维护困难,且查询条件无法下推
创建虚拟表
CREATE VTABLE 语句用于创建普通虚拟表和以虚拟超级表为模板创建虚拟子表。
创建虚拟超级表
见 创建超级表 中的 VIRTUAL 参数。
创建虚拟普通表
CREATE VTABLE [IF NOT EXISTS] [db_name].vtb_name ts_col_name timestamp, (create_definition[ ,create_definition] ...) create_definition:vtb_col_name column_definitioncolumn_definition:type_name [FROM [db_name.]table_name.col_name]
创建虚拟子表
CREATE VTABLE [IF NOT EXISTS] [db_name].vtb_name (create_definition[ ,create_definition] ...) USING [db_name.]stb_name [(tag_name [, tag_name] ...)] TAGS (tag_value [, tag_value] ...)create_definition:[stb_col_name FROM] [db_name.]table_name.col_nametag_value:const_value
使用说明
- 虚拟表(列)名命名规则参见 名称命名规则。
- 表名最大长度为 192。
- 表的第一个字段必须是 TIMESTAMP,并且系统自动将其设为主键。
- 表的每行长度不能超过 64KB(注意:每个 VARCHAR/NCHAR/GEOMETRY 类型的列还会额外占用 2 个字节的存储位置)。
- 使用数据类型 VARCHAR/NCHAR/GEOMETRY,需指定其最长的字节数,如 VARCHAR(20),表示 20 字节。
- 创建虚拟表时使用 FROM 来指定列的数据源,支持使用 db_name 跨库指定数据源,不指定 db_name 时默认使用当前 use 的数据库,若不指定 db_name 且未 use 数据库,则会报错。
- 创建虚拟表时不显式的指定 ts 列的数据源,ts 列的取值是查询虚拟表时查询语句中包含的所有列对应的原始表的主键时间戳合并的结果。
- 虚拟超级表下只支持创建虚拟子表,虚拟子表也只能以虚拟超级表为模版来创建。
- 创建虚拟表时需要保证虚拟表中的列、标签和指定的数据来源列、标签的数据类型相同,否则会报错。
- 在同一个数据库内,虚拟表名称不允许重名,虚拟表名和表名也不允许重名。虚拟表名和视图名允许重名(不推荐)当出现视图与虚拟表名重名时,写入、查询、授权、回收权限等操作优先使用同名表。
- 创建虚拟子表和虚拟普通表时,使用 FROM 指定某一列的数据来源时,该列只能来源于普通子表或普通表,不支持来源于超级表、视图或其他虚拟表。也不支持来源于有复合主键的表。
查询虚拟表
虚拟表与正常表无论是查询语法还是范围都没有区别,不同之处在于虚拟表所呈现的数据集在不同的查询中可能是不相同的,具体可以参考虚拟表数据生成规则。
虚拟表数据生成规则
- 虚拟表以时间戳为基准,对多个原始表的数据进行对齐。
- 如果多个原始表在相同时间戳下有数据,则这些列的值组合成同一行;否则,对于缺失的列,填充 NULL。
- 虚拟表的时间戳的值是查询中包含的所有列所在的原始表的时间戳的并集,因此当不同查询选择列不同时可能出现结果集行数不一样的情况。
- 用户可以从多个表中选择任意列进行组合,未选择的列不会出现在虚拟表中。
示例
假设有表 t1、t2、t3 结构和数据如下:
| t1 | t2 | t3 | ||||||
|---|---|---|---|---|---|---|---|---|
| ts | value | ts | value | ts | value1 | value2 | ||
| 0:00:01 | 1 | |||||||
| 0:00:02 | 20 | |||||||
| 0:00:03 | 300 | 3000 | ||||||
| 0:00:04 | 4 | 0:00:04 | 40 | 0:00:03 | ||||
| 0:00:05 | 50 | 0:00:05 | 500 | 5000 | ||||
并且有虚拟普通表 v1,创建方式如下:
create vtable v1 (ts timestamp,c1 int from t1.value,c2 int from t2.value,c3 int from t3.value1,c4 int from t3.value2);
那么根据虚拟表对于多表数据的整合规则,执行如下查询时:
select * from v1;
结果如下:
| v1 | ||||
|---|---|---|---|---|
| ts | c1 | c2 | c3 | c4 |
| 0:00:01 | 1 | |||
| 0:00:02 | 20 | |||
| 0:00:03 | 300 | 3000 | ||
| 0:00:04 | 4 | 40 | ||
| 0:00:05 | 50 | 500 | 5000 | |
如果没有选择全部列,只是选择了部分列,查询的结果只会包含选择的列的原始表的时间戳,例如执行如下查询:
select c1, c2 from v1;
得到的结果如下图所示:
| v1 | ||||
|---|---|---|---|---|
| ts | c1 | c2 | ||
| 0:00:01 | 1 | |||
| 0:00:02 | 20 | |||
| 0:00:04 | 4 | 40 | ||
| 0:00:05 | 50 | |||
因为 c1、c2 列对应的原始表 t1、t2 中没有 0:00:03 这个时间戳,所以最后的结果也不会包含这个时间戳。
修改虚拟普通表
ALTER VTABLE [db_name.]vtb_name alter_table_clausealter_table_clause: {ADD COLUMN vtb_col_name vtb_column_type [FROM table_name.col_name]| DROP COLUMN vtb_col_name| ALTER COLUMN vtb_col_name SET {table_name.col_name | NULL }| MODIFY COLUMN col_name column_type| RENAME COLUMN old_col_name new_col_name
}
使用说明
对虚拟普通表可以进行如下修改操作
- ADD COLUMN:添加列。
- DROP COLUMN:删除列。
- MODIFY COLUMN:修改列定义,如果数据列的类型是可变长类型,那么可以使用此指令修改其宽度,只能改大,不能改小。如果虚拟表该列已指定数据源,那么修改列宽会因为修改后的列宽和数据源的列宽不匹配而报错,可以先将数据源置为空后再修改列宽。
- RENAME COLUMN:修改列名称。
- ALTER COLUMN … SET:修改列的数据源。SET NULL 表示将虚拟表某列的数据源置为空。
增加列
ALTER VTABLE vtb_name ADD COLUMN vtb_col_name vtb_col_type [FROM [db_name].table_name.col_name]
删除列
ALTER VTABLE vtb_name DROP COLUMN vtb_col_name
修改列宽
ALTER VTABLE vtb_name MODIFY COLUMN vtb_col_name data_type(length);
修改列名
ALTER VTABLE vtb_name RENAME COLUMN old_col_name new_col_name
修改列的数据源
ALTER VTABLE vtb_name ALTER COLUMN vtb_col_name SET {[db_name.]table_name.col_name | NULL}
修改虚拟子表
ALTER VTABLE [db_name.]vtb_name alter_table_clausealter_table_clause: {ALTER COLUMN vtb_col_name SET table_name.col_name| SET TAG tag_name = new_tag_value
}
使用说明
- 对虚拟子表的列和标签的修改,除了更改标签值以外,都要通过虚拟超级表才能进行。
修改虚拟子表标签值
ALTER VTABLE tb_name SET TAG tag_name1=new_tag_value1, tag_name2=new_tag_value2 ...;
修改列的数据源
ALTER VTABLE vtb_name ALTER COLUMN vtb_col_name SET {[db_name.]table_name.col_name | NULL}
删除虚拟表
DROP VTABLE [IF EXISTS] [dbname].vtb_name;
查看虚拟表的信息
显示某个数据库下所有虚拟表
如下 SQL 语句可以列出当前数据库中的所有虚拟表名。
SHOW [NORMAL | CHILD] [db_name.]VTABLES [LIKE 'pattern'];
使用说明
- 如果没有指定 db_name,显示当前数据库下的所有虚拟普通表和虚拟子表的信息。若没有使用数据库并且没有指定 db_name, 则会报错 database not specified。可以使用 LIKE 对表名进行模糊匹配。NORMAL 指定只显示虚拟普通表信息,CHILD 指定只显示虚拟子表信息。
显示虚拟表创建语句
SHOW CREATE VTABLE [db_name.]vtable_name;
显示 vtable_name 指定的虚拟表的创建语句。支持虚拟普通表和虚拟子表。常用于数据库迁移。对一个已经存在的虚拟表,返回其创建语句;在另一个集群中执行该语句,就能得到一个结构完全相同的虚拟表。
获取虚拟表结构信息
DESCRIBE [db_name.]vtb_name;
查看所有虚拟表信息
SELECT ... FROM information_schema.ins_tables where type = 'VIRTUAL_NORMAL_TABLE' or type = 'VIRTUAL_CHILD_TABLE';
写入虚拟表
不支持向虚拟表中写入数据,以及不支持删除虚拟表中的数据。虚拟表只是对原始表进行运算后的计算结果,是一张逻辑表,因此只能对其进行查询,不可以写入或删除数据。
虚拟表与视图
虚拟表与视图看起来相似,但是有很多不同点:
| 属性 | 虚拟表 (Virtual Table) | 视图 (View) |
|---|---|---|
| 定义 | 虚拟表是一种动态数据结构,根据多表的列和时间戳组合规则生成逻辑表。 | 视图是一种基于 SQL 查询的虚拟化表结构,用于保存查询逻辑的定义。 |
| 数据来源 | 来自多个原始表,可以动态选择列,并通过时间戳对齐数据。 | 来自单个或多个表的查询结果,通常是一个复杂的 SQL 查询。 |
| 数据存储 | 不实际存储数据,所有数据在查询时动态生成。 | 不实际存储数据,仅保存 SQL 查询逻辑。 |
| 时间戳处理 | 通过时间戳对齐将不同表的列整合到统一的时间轴上。 | 不支持时间戳对齐,数据由查询逻辑直接决定。 |
| 更新机制 | 动态更新,原始表数据变更时,虚拟表数据实时反映变化。 | 动态更新,但依赖于视图定义的查询逻辑,不涉及对齐或数据整合。 |
| 功能特性 | 支持空值填充和插值(如 prev、next、linear)。 | 不支持内置填充和插值功能,需通过查询逻辑自行实现。 |
| 应用场景 | 时间序列对齐、跨表数据整合、多源数据对比分析等场景。 | 简化复杂查询逻辑、限制用户访问、封装业务逻辑等场景。 |
| 性能 | 由于多表对齐和空值处理,查询复杂度可能较高,尤其在数据量大时。 | 性能通常取决于视图的查询语句复杂度,与单表查询性能相似。 |
不支持虚拟表和视图之间的相互转化,如根据虚拟表建立视图或者根据视图建立虚拟表。
虚拟表的权限
权限说明
虚拟表的权限分为 READ、WRITE 两种,查询操作需要具备 READ 权限,对虚拟表本身的删除和修改操作需要具备 WRITE 权限。
语法
授权
GRANT privileges ON [db_name.]vtable_name TO user_name
privileges: {ALL,| priv_type [, priv_type] ...
}
priv_type: {READ| WRITE
}
回收权限
REVOKE privileges ON [db_name.]vtable_name FROM user_name
privileges: {ALL,| priv_type [, priv_type] ...
}
priv_type: {READ| WRITE
}
权限规则
- 虚拟表的创建者和 root 用户默认具备所有权限。
- 用户可以通过 dbname.vtbname 来为指定的虚拟表表(包括虚拟超级表和虚拟普通表)授予或回收其读写权限,不支持直接对虚拟子表授予或回收权限。
- 虚拟子表和虚拟超级表不支持基于标签的授权(表级授权),虚拟子表继承虚拟超级表的权限。
- 对其他用户进行授权与回收权限可以通过 GRANT 和 REVOKE 语句进行,该操作只能由 root 用户进行。
- 具体相关权限控制细则总结如下:
| 序号 | 操作 | 权限要求 |
|---|---|---|
| 1 | CREATE VTABLE | 用户对虚拟表所属数据库有 WRITE 权限 且 用户对虚拟表的数据源对应的原始表有 READ 权限。 |
| 2 | DROP/ALTER VTABLE | 用户对虚拟表有 WRITE 权限,若要指定某一列的数据源,需要同时对数据源对应的原始表有 READ 权限。 |
| 3 | SHOW VTABLES | 无 |
| 4 | SHOW CREATE VTABLE | 无 |
| 5 | DESCRIBE VTABLE | 无 |
| 6 | 系统表查询 | 无 |
| 7 | SELECT FROM VTABLE | 操作用户对虚拟表有 READ 权限 |
| 8 | GRANT/REVOKE | 只有 root 用户有权限 |
使用场景
| SQL 查询 | SQL 写入 | STMT 查询 | STMT 写入 | 订阅 | 流计算 |
|---|---|---|---|---|---|
| 支持 | 不支持 | 不支持 | 不支持 | 不支持 | 支持 |
访问官网
更多内容欢迎访问 TDengine 官网
相关文章:
TDengine 重磅功能虚拟表
简介 虚拟表功能是 TDengine 最近刚发现的 3.3.6.0 版本中一项重磅级新功能,虚拟表可理解为在原来查询基础上做了一层逻辑表,在数据查询建模时即可不依赖底层物理存储表,直接通过虚拟表进行数据查询建模,这样逻辑上会更加清晰&am…...
3.9/Q2,Charls最新文章解读
文章题目:Association between remnant cholesterol and depression in middle-aged and older Chinese adults: a population-based cohort study DOI:10.3389/fendo.2025.1456370 中文标题:中国中老年人残留胆固醇与抑郁症的关系࿱…...
Java Lambda 表达式提升效率
lambda 表达式的应用场景 Stream 的应用场景 Lambda/Stream 的进一步封装 自定义函数式接口(用 jdk 自带的函数式接口也可以) https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html import java.io.Serializable;/*** 可序…...
人工智能混合编程实践:C++ ONNX进行图像超分重建
人工智能混合编程实践:C++ ONNX进行图像超分重建 前言相关介绍C++简介ONNX简介ONNX Runtime 简介**核心特点**图像超分辨率重建简介应用场景前提条件实验环境项目结构使用C++ ONNX进行图像超分重建sr_main.cpp参考文献前言 由于本人水平有限,难免出现错漏,敬请批评改正。更多…...
K8S学习之基础七十四:部署在线书店bookinfo
部署在线书店bookinfo 在线书店-bookinfo 该应用由四个单独的微服务构成,这个应用模仿在线书店的一个分类,显示一本书的信息,页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本…...
Python不可变数据类型全解析:原理、优势与实战指南
目录 引言:为什么Python要区分可变与不可变? 一、不可变数据类型的核心特性 二、五大不可变数据类型深度解析 三、不可变数据类型的三大核心优势 四、不可变数据类型的典型应用场景 五、不可变 vs 可变:如何选择? 六、实战技…...
六.FFmpeg对mp4文件操作(ubuntu)
一.抽取aac数据 1.代码抽取aac没有声音,使用ffmpeg命令行也无法转换为wav 问题解决:ADTS头的采样率没有设置正确,av_dump_format 获取视频信息的时候可以看到aac的详细信息。 void Widget::adts_header(char *szAdtsHeader, int dataLen) …...
Apache Doris 2025 Roadmap:构建 GenAI 时代实时高效统一的数据底座
在全球 290 位开发者的协作下,Apache Doris 在 2024 年完成了 7000 次代码提交,并发布了 22 个版本,实现在实时分析、湖仓一体和半结构化数据分析等核心场景的技术突破及创新。 2025 年,Apache Doris 社区将秉承“以场景驱动创新…...
HTTP数据传输的几个关键字Header
本文着重针对http在传输数据时的几种封装方式进行描述。 1. Content-Type(描述body内容类型以及字符编码) HTTP的Content-Type用于定义数据传输的媒体类型(MIME类型),主要分为以下几类: (一)、基础文本类型 text/plain …...
二极管正负极区分
二极管正负极区分 二极管是一种具有单向导电性的半导体器件,正确区分正负极对于其使用非常重要。以下是几种常见的二极管正负极区分方法: 1. 外观标识 有标记的二极管 色环或色点:许多二极管在表面会有一个色环或色点,这个标记…...
CyclicBarrier、Semaphore、CountDownLatch的区别,适用场景
CyclicBarrier、Semaphore 和 CountDownLatch 是 Java 并发包中用于线程协作的工具类,它们虽然都与线程同步相关,但设计目的和使用场景有显著差异。以下是它们的核心区别和典型应用场景: 1. CountDownLatch 核心机制 一次性计数器…...
【c++深入系列】:类与对象详解(中)
🔥 本文专栏:c 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 不是因为看到希望才坚持,而是坚持了才能看到希望 那么上一篇博客我讲解了什么是类和对象以及类和对象是怎么定义的࿰…...
解锁界面设计密码,打造极致用户体验
界面设计是对软件、网站、移动应用等产品的用户界面进行设计的过程,旨在为用户提供美观、易用、高效的交互体验。以下是关于界面设计的一些主要方面: 一、设计原则 用户中心原则:以用户为中心,了解用户的需求、期望、行为和习惯…...
用Python和Pygame创造粉色粒子爱心:3D渲染的艺术
引言 在计算机图形学中,3D效果的2D渲染是一个迷人的领域。今天,我将分享一个使用Python和Pygame库创建的粉色粒子爱心效果。这个项目不仅视觉效果惊艳,而且代码简洁易懂,非常适合图形编程初学者学习3D渲染的基础概念。 项目概述…...
汽车 HMI 设计的发展趋势与设计要点
一、汽车HMI设计的发展历程与现状 汽车人机交互界面(HMI)设计经历了从简单到复杂、从单一到多元的演变过程。2012年以前,汽车HMI主要依赖物理按键进行操作,交互方式较为单一。随着特斯拉Model S的推出,触控屏逐渐成为…...
《AI大模型应知应会100篇》第56篇:LangChain快速入门与应用示例
第56篇:LangChain快速入门与应用示例 前言 最近最火的肯定非Manus和OpenManus莫属,因为与传统AI工具仅提供信息不同,Manus能完成端到端的任务闭环。例如用户发送“筛选本月抖音爆款视频”,它会自动完成: 爬取平台数据…...
vue-office 支持预览多种文件(docx、excel、pdf、pptx)预览的vue组件库
官网地址:https://github.com/501351981/vue-office 支持多种文件(docx、excel、pdf、pptx)预览的vue组件库,支持vue2/3。也支持非Vue框架的预览。 1.在线预览word文件(以及本地上传预览) 1.1:下载组件库 npm inst…...
Java 大视界 -- Java 大数据在智能农业无人机植保作业路径规划与药效评估中的应用(165)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
哈希表系列一>两数之和
目录 题目:方法:暴力代码:优化后代码: 题目: 链接: link 方法: 暴力代码: public int[] twoSum(int[] nums, int target) {解法一:暴力解法:int n nums.length;for(int…...
【SPP】深入解析蓝牙 L2CAP 协议在SPP中的互操作性要求
在蓝牙协议体系中,L2CAP(Logical Link Control and Adaptation Protocol)作为基带协议与高层协议之间的桥梁,承担着数据分帧、协议复用、QoS协商等核心功能。当涉及串行端口通信时,L2CAP的规范实现直接决定了设备间数据传输的可靠性、效率及兼容性。本文基于《Serial Port…...
CAD插件实现:自动递增编号(前缀、后缀、位数等)——CADc#实现
cad中大量输入一定格式的递增编号时,可用插件实现,效果如下: ①本插件可指定数字位数、起始号码、加前缀、后缀、文字颜色等(字体样式和文字所在图层为cad当前图层和当前字体样式)。 ②插件采用Jig方式,即…...
Spring | Spring、Spring MVC 和 Spring Boot 的区别
关注:CodingTechWork 引言 在 Java 开发领域,Spring、Spring MVC 和 Spring Boot 是三个经常被提及的概念。它们之间既有联系又有区别,对于初学者来说可能会感到困惑。本文将详细介绍它们的区别,并通过示例代码帮助读者更好地理解…...
观察者模式在Java微服务间的使用
一.、使用RabbitMQ来实现 (1) 生产者(订单微服务) import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.stereotype.Service;Service public class OrderService {private final RabbitTemplate rabbitTemplate;…...
C语言--回文字符串
输入:字符串,判断是否是回文字符串,例如abcba输出Yes 输出:是否 代码 思路:使用两个指针分别指向头和尾,依次对比第一个元素和最后一个元素,第二个和倒数第二个元素,如果遇到不相同…...
【云计算物理网络】数据中心网络架构设计
云计算的物理基础:数据中心网络架构设计 一、技术背景:从“三层架构”到“云原生网络”二、技术特点:云数据中心网络的四大支柱三、技术细节:CLOS架构的实现挑战四、未来方向:从“连接设备”到“感知服务”结语&#x…...
Coco-AI 支持嵌入,让你的网站拥有 AI 搜索力
在之前的实践中,我们已经成功地把 Hexo、Hugo 等静态博客和 Coco-AI 检索系统打通了:只要完成向量化索引,就可以通过客户端问答界面实现基于内容的智能检索。 这一层已经很好用了,但总觉得少了点什么—— 比如用户还得专门打开一…...
批处理脚本的主要解析规则
批处理脚本的主要解析规则 批处理脚本(Batch files)有一套独特的解析规则,这些规则在很多情况下不太直观,但了解它们对于编写可靠的脚本至关重要。以下是最重要的一些规则: 1. 变量扩展规则 标准变量扩展 (%变量%) 解析时扩展:…...
TRDI 公司的RiverPro 和 RioPro ADCP 用户指南
TRDI 公司 RiverPro 和 RioPro ADCP 用户指南 简介第一章 - 概述第二章 - 安装第三章 - 采集数据第四章 - 维护第五章 - 测试RIVERPRO/RIOPRO第六章 - 故障排除第七章 - 将系统返回TRDI进行维修第八章 - 规格第九章 - 命令第十章 - 输出数据格式附录A-合规通知首次完整翻译《Ri…...
Linux 基础入门操作 前言 linux操作指令介绍
1 linux 目录介绍 Linux 文件系统采用层次化的目录结构,所有目录都从根目录 / 开始 1.1 核心目录 / (根目录) 整个文件系统的起点、包含所有其他目录和文件 /bin (基本命令二进制文件) 存放系统最基本的shell命令:如 ls, cp, mv, rm, cat 等&#…...
【总结】SQL注入防护手段
1、对提交的数据进行数据类型判断,比如id值必须是数字:is_numeric($id) 2、对提交的数据进行正则匹配,禁止出现注入语句,比如union、or、and等 3、对提交数据进行特殊符号转义,比如单引号、双引…...
