时序数据库在海量数据写入场景中扮演着关键角色,其写入性能直接影响物联网、工业互联网等实时数据采集系统的整体效率。TDengine作为一款专为时序数据设计的时序数据库,提供了多种高效的数据写入方式,从标准SQL到无模式写入,从单条插入到批量写入,覆盖了各类业务场景。本文将全面介绍TDengine的数据写入机制、无模式写入协议以及写入性能优化技巧,帮助开发者构建高性能的数据采集管道。
一、TDengine多种写入方式概览
TDengine支持灵活多样的数据写入方式,开发者可以根据业务场景选择最适合的方案。以下是TDengine支持的主要写入方式:
| 写入方式 | 适用场景 | 特点 |
|---|---|---|
| 标准SQL写入 | 少量数据、调试场景 | 简单直观,兼容标准SQL语法 |
| 批量写入 | 大数据量导入、定时任务 | 高吞吐,减少网络交互 |
| 多表写入 | 多设备同时上报 | 一次请求写入多张子表 |
| 自动建表写入 | 动态设备接入 | 无需预先建表,自动创建子表 |
| 无模式写入 | 跨平台迁移、多协议接入 | 兼容InfluxDB/OpenTSDB协议 |
1.1 标准SQL写入
最基础的写入方式,使用标准INSERT语句:
-- 向子表写入单条数据
INSERT INTO d1001 (ts, current, voltage, phase)
VALUES ('2025-06-03 10:00:00', 10.5, 220, 0.8);
-- 向多张子表写入数据
INSERT INTO d1001 VALUES ('2025-06-03 10:01:00', 10.2, 219, 0.81)
d1002 VALUES ('2025-06-03 10:01:00', 11.3, 221, 0.79);
1.2 批量写入
批量写入是提升写入性能的关键手段。TDengine支持在一条INSERT语句中写入大量数据:
-- 批量写入:一次插入多行数据
INSERT INTO d1001 VALUES
('2025-06-03 10:00:00', 10.5, 220, 0.8)
('2025-06-03 10:01:00', 10.2, 219, 0.81)
('2025-06-03 10:02:00', 10.8, 221, 0.78)
('2025-06-03 10:03:00', 10.1, 218, 0.82);
批量写入时,TDengine会在服务端进行写入优化,将多条记录合并后一次性写入存储引擎,大幅减少磁盘I/O次数。
二、无模式写入(Schemaless)
TDengine的无模式写入功能是其一大亮点,允许在不预先创建表结构的情况下直接写入数据。这一特性极大简化了数据接入流程,特别适合设备动态增减的物联网场景。
2.1 兼容InfluxDB Line Protocol
TDengine支持InfluxDB的行协议格式,方便从InfluxDB迁移或使用InfluxDB生态工具:
-- 使用InfluxDB Line Protocol格式写入
-- 语法: <measurement>,<tags> <fields> <timestamp>
INSERT INTO stb1,t0=1,t1=2 c0=1.0,c1="hello" 1626006833639ms
其中:
stb1为超级表名称t0=1,t1=2为标签值c0=1.0,c1="hello"为数据列1626006833639ms为时间戳(支持ms/us/ns/s等多种精度)
2.2 兼容OpenTSDB JSON/telnet格式
TDengine同时兼容OpenTSDB的数据写入协议:
// OpenTSDB JSON格式
{
"metric": "cpu.usage",
"timestamp": 1626006833,
"value": 75.5,
"tags": {
"host": "server01",
"region": "cn-beijing"
}
}
# OpenTSDB telnet格式
put cpu.usage 1626006833 75.5 host=server01 region=cn-beijing
2.3 自动建表机制
无模式写入的核心优势在于自动建表。当写入的数据对应的子表不存在时,TDengine会自动创建超级表和子表:
-- 配置自动建表参数
CREATE DATABASE power
SML_AUTO_CREATE_DB ON -- 无模式写入时自动创建数据库
SML_CHILD_TABLE 'auto_ct' -- 自动建表时子表命名规则
SML_TZ 'Asia/Shanghai'; -- 时区设置
自动建表的规则如下:
- 若超级表不存在,自动创建超级表
- 若子表不存在,根据标签值自动创建子表
- 子表名称由
SML_CHILD_TABLE参数控制
三、写入优化核心技术
3.1 WAL预写日志
WAL(Write Ahead Log)是TDengine保证数据不丢失的核心机制。写入流程如下:
客户端写入请求 → WAL预写日志 → 内存缓冲区 → 返回成功 → 异步刷盘到数据文件
WAL的工作原理:
- 先写日志再写内存:数据先持久化到WAL文件,再写入内存缓冲区
- 崩溃恢复保障:系统异常重启时,通过重放WAL恢复未刷盘的数据
- 顺序写入优化:WAL采用追加写入方式,充分利用磁盘顺序写性能
-- WAL相关配置参数
ALTER DATABASE mydb WAL_LEVEL 1; -- WAL日志级别
-- 0: 不写WAL; 1: 写WAL但不执行fsync; 2: 写WAL并执行fsync
3.2 批量写入参数优化
TDengine提供了多个参数用于控制批量写入行为:
| 参数 | 默认值 | 说明 |
|---|---|---|
| maxInsertBatchRows | 1000000 | 单次批量写入的最大行数 |
| maxInsertBatchCols | 1000000 | 单次批量写入的最大列数 |
| maxSQLLength | 1048576 | 单条SQL语句的最大长度(字节) |
-- 通过taos.cfg调整批量写入参数
maxInsertBatchRows 1000000
maxInsertBatchCols 1000000
最佳实践建议:
- 每批写入数据量建议在1000~100000行之间
- 单条SQL不宜过大,避免超过
maxSQLLength限制 - 根据网络带宽和内存情况调整批量大小
3.3 Buffer配置与vgroups规划
合理的Buffer和vgroups配置是写入性能调优的基础:
-- 创建高性能写入数据库
CREATE DATABASE iot_data
BUFFER 1024 -- 每个vnode的写缓存大小(MB)
VGROUPS 8 -- 虚拟节点组数量
WAL_LEVEL 1 -- WAL级别
PRECISION 'ms'; -- 时间精度
vgroups规划原则:
- vgroups数量建议不超过数据节点(dnode)的CPU核数
- 每个vgroup至少分配256MB的Buffer
- 写入吞吐量高的场景适当增加vgroups数量
四、taosAdapter数据接入
taosAdapter是TDengine提供的数据接入组件,支持多种主流监控和数据采集工具的协议:
4.1 支持的数据接入协议
| 协议/工具 | 用途 | 配置方式 |
|---|---|---|
| Telegraf | 通用数据采集 | taosAdapter配置文件 |
| StatsD | 应用指标采集 | taosAdapter配置文件 |
| collectd | 系统指标采集 | taosAdapter配置文件 |
| Prometheus | 监控数据写入 | taosAdapter配置文件 |
| InfluxDB Line Protocol | 兼容写入 | RESTful API |
4.2 taosAdapter配置示例
# taosAdapter配置文件(部分)
telegraf:
enable: true
port: 6044
db: telegraf_db
prometheus:
enable: true
port: 6043
db: prometheus_db
statsd:
enable: true
port: 6045
db: statsd_db
通过taosAdapter,用户无需编写代码即可将Telegraf、Prometheus等工具采集的数据直接写入TDengine,大幅降低了数据接入的复杂度。
五、代码示例:多语言写入实践
5.1 Python写入示例
import taos
# 建立连接
conn = taos.connect(host='localhost', port=6030, user='root', password='taosdata')
cursor = conn.cursor()
# 创建数据库和超级表
cursor.execute('CREATE DATABASE IF NOT EXISTS power PRECISION "ms"')
cursor.execute('USE power')
cursor.execute('''
CREATE STABLE IF NOT EXISTS meters (
ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT
) TAGS (location INT, groupId INT)
''')
# 自动建表写入(使用SML协议)
# 先确保数据库配置了SML_AUTO_CREATE_DB ON
cursor.execute('''
INSERT INTO power.meters _s0 _i0 _i1
USING power.meters TAGS(1, 1)
VALUES ('2025-06-03 10:00:00', 10.5, 220, 0.8)
''')
# 批量写入
sql = 'INSERT INTO power.meters'
for i in range(1000):
ts = f'2025-06-03 10:{i//60:02d}:{i%60:02d}'
sql += f' _s{i} _i{i//100} _i{i%10} VALUES (\'{ts}\', {10.0+i*0.1}, 220, 0.8)'
cursor.execute(sql)
cursor.close()
conn.close()
5.2 JDBC写入示例
import com.taosdata.jdbc.TSDBDriver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class TDengineWriteExample {
public static void main(String[] args) throws Exception {
String url = "jdbc:TAOS://localhost:6030/power?charset=UTF-8";
Connection conn = DriverManager.getConnection(url, "root", "taosdata");
Statement stmt = conn.createStatement();
// 批量写入
StringBuilder sb = new StringBuilder("INSERT INTO ");
for (int i = 0; i < 1000; i++) {
sb.append(String.format(
"d%d VALUES ('2025-06-03 10:%02d:%02d', %f, %d, %f) ",
i, i / 60, i % 60, 10.0 + i * 0.1, 220, 0.8
));
}
stmt.execute(sb.toString());
stmt.close();
conn.close();
}
}
5.3 RESTful API写入示例
# 通过RESTful API写入数据
curl -u root:taosdata -d 'INSERT INTO power.meters
_s0 _i0 _i1 USING power.meters TAGS(1, 1)
VALUES ("2025-06-03 10:00:00", 10.5, 220, 0.8)' \
http://localhost:6041/rest/sql/power
六、写入性能调优总结
6.1 异步写入策略
对于对写入延迟不敏感但吞吐量要求极高的场景,可以采用异步写入策略:
- 调整WAL级别:将
WAL_LEVEL设为1,避免每次写入都执行fsync - 增大Buffer:适当增大每个vnode的写缓存,减少刷盘频率
- 合理设置vgroups:根据CPU核数和数据量规划vgroups数量
6.2 性能调优检查清单
| 调优项 | 推荐配置 | 说明 |
|---|---|---|
| BUFFER | 256~1024 MB | 根据可用内存调整 |
| VGROUPS | 不超过CPU核数 | 过多会导致资源竞争 |
| WAL_LEVEL | 1(推荐) | 平衡性能与可靠性 |
| maxInsertBatchRows | 1000000 | 保持默认即可 |
| 批量大小 | 1000~100000行 | 根据实际场景测试 |
结语
TDengine作为一款专为时序数据设计的时序数据库,在数据写入方面提供了丰富的功能和极致的性能优化。从标准SQL写入到无模式写入,从WAL预写日志到批量写入优化,TDengine为开发者构建高性能数据采集系统提供了完整的解决方案。通过合理配置Buffer、vgroups和WAL参数,结合taosAdapter的多协议接入能力,TDengine能够轻松应对每秒千万级数据点的写入需求,是物联网和工业互联网场景下时序数据库的理想选择。
























