02 数据模型 > 01 数据库创建与参数详解 --- 所有 Option 逐一说明

适用版本:TDengine v3.x(v3.3.x / v3.4.x) | 最后更新:2026-05-16
概述
数据库(Database)是 TDengine 中最顶层的数据组织单元。每个数据库拥有独立的存储参数、保留策略和副本配置。理解数据库的创建参数对于生产环境的性能调优和容量规划至关重要。
本文涵盖:
- CREATE DATABASE 的完整语法和所有参数
- 每个参数的含义、默认值、取值范围、调优建议
- ALTER DATABASE 可修改的参数
- 数据库创建时内部的资源分配逻辑
核心概念速查表
| 概念 | 说明 |
|---|---|
| Database | 数据的最顶层容器,所有表都必须属于某个数据库 |
| VGroup | 数据库内的虚拟存储组,每个 VGroup 管理一部分子表 |
| Hash 路由 | 表名通过 hash 映射到对应 VGroup,决定数据存储位置 |
| KEEP | 数据保留时长,超期数据自动删除 |
| DURATION | 单个数据文件的时间跨度 |
| WAL | 预写日志,保障写入的持久性 |
| RSMA | 滚动聚合(Rollup SMA),自动降采样 |
详细解析
1. 基础语法
sql
CREATE DATABASE [IF NOT EXISTS] db_name [database_options];
ALTER DATABASE db_name alter_database_options;
DROP DATABASE [IF EXISTS] db_name;
数据库命名规则:
- 最大长度:64 个字符
- 允许字符:字母、数字、下划线
- 不能以数字开头
- 大小写不敏感(内部统一转为小写存储)
2. 全部参数一览
2.1 存储结构参数(不可修改)
这些参数在数据库创建后不可更改,需要在建库时仔细规划。
VGROUPS --- VGroup 数量
| 属性 | 值 |
|---|---|
| 默认值 | 2 |
| 取值范围 | [1, 1024] |
| 可否修改 | ❌ |
含义:数据库中虚拟分组的数量。每个 VGroup 对应一组 VNode(副本),独立管理一部分子表数据。
Hash 路由原理 :系统将 [0, 4294967295](UINT32 最大值)均匀分成 N 段,每个 VGroup 负责一段。写入时根据表名计算 hash 值,落入哪一段就归哪个 VGroup 管理。
Hash 范围分配示例(VGROUPS = 4):
VGroup 1: [0, 1073741823]
VGroup 2: [1073741824, 2147483647]
VGroup 3: [2147483648, 3221225471]
VGroup 4: [3221225472, 4294967295]
选择建议:
- CPU 核数 × DNode 数量 是合理的上限参考
- 子表数量 < 10万:VGROUPS 2~4 即可
- 子表数量 10万~100万:VGROUPS 4~16
- 子表数量 > 100万:VGROUPS 16~64
- 过多 VGroup 会增加 MNode 元数据管理压力和查询合并开销
PRECISION --- 时间戳精度
| 属性 | 值 |
|---|---|
| 默认值 | 'ms' |
| 取值范围 | 'ms'(毫秒)、'us'(微秒)、'ns'(纳秒) |
| 可否修改 | ❌ |
含义:数据库内所有时间戳列的精度。
选择建议:
- 工业物联网一般采集频率 ≤ 1000Hz →
ms足够 - 金融交易、高频采集 →
us - 物理实验、纳秒级需求 →
ns - 精度越高,时间戳占用的存储空间相同(都是 8 字节),但 SQL 中的时间值写法需匹配
DURATION --- 数据文件时间跨度
| 属性 | 值 |
|---|---|
| 默认值 | 14400 分钟(10 天) |
| 取值范围 | [60 分钟, 3650 天] |
| 可否修改 | ❌ |
含义:每个时序数据文件覆盖的时间范围。系统按时间段将数据组织到不同的文件组中。
DURATION 与文件组的关系:
假设 DURATION = 10d, KEEP = 365d:
时间轴:
|←10天→|←10天→|←10天→| ... |←10天→|
[文件1] [文件2] [文件3] [文件37]
查询 "最近 1 小时" → 只需读取最后 1 个文件
查询 "最近 30 天" → 需要读取 3 个文件
过期删除 → 直接删除整个文件(高效)
选择建议:
KEEP / DURATION≈ 文件总数,建议文件数在 10~100 之间- DURATION 太小 → 文件过多,元数据开销大
- DURATION 太大 → 过期删除粒度粗,查询时可能读取过多无关数据
- 经验公式:
DURATION = KEEP / 30(保留 1 年则每个文件约 12 天)
PAGESIZE --- 元数据引擎页大小
| 属性 | 值 |
|---|---|
| 默认值 | 4 KB |
| 取值范围 | [1, 16384] KB |
| 可否修改 | ❌ |
含义:VNode 内部元数据存储引擎(TDB)的页大小,用于存储子表列表、Tag 索引等。
TSDB_PAGESIZE --- 时序存储引擎页大小
| 属性 | 值 |
|---|---|
| 默认值 | 4 KB |
| 取值范围 | [1, 16384] KB |
| 可否修改 | ❌ |
含义:TSDB(时序数据存储引擎)的数据页大小。影响数据压缩块的粒度和 I/O 对齐。
选择建议:
- 列数 < 100:默认 4KB 即可
- 列数多(宽表场景):考虑增大到 8KB 或 16KB,避免单行跨页
MAXROWS --- 数据块最大行数
| 属性 | 值 |
|---|---|
| 默认值 | 4096 |
| 取值范围 | [200, 10000000] |
| 可否修改 | ❌ |
含义:TSDB 中单个数据块包含的最大行数。到达此行数后开启新数据块。
COMP --- 压缩级别
| 属性 | 值 |
|---|---|
| 默认值 | 2 |
| 取值范围 | 0、1、2 |
| 可否修改 | ❌ |
| 值 | 含义 | 压缩率 | CPU 开销 |
|---|---|---|---|
| 0 | 不压缩 | 1:1 | 无 |
| 1 | 一阶压缩(LZ4) | 约 2:1~5:1 | 低 |
| 2 | 二阶压缩(类型特化 + LZ4) | 约 5:1~20:1 | 中 |
二阶压缩会根据列的数据类型选择最优编码方式(如时间戳差分编码、整数 ZigZag + 变长编码等),然后再做 LZ4 压缩。
TABLE_PREFIX --- 表名哈希前缀长度
| 属性 | 值 |
|---|---|
| 默认值 | 0 |
| 取值范围 | [-191, 191] |
| 可否修改 | ❌ |
含义:控制表名 hash 路由时,使用或忽略表名的前 N 个字符。
- 正数 N:hash 时只取表名的前 N 个字符
- 负数 -N:hash 时忽略表名的前 N 个字符
- 0:使用完整表名
使用场景 :当表名有统一前缀(如 device_001、device_002),设置 TABLE_PREFIX = -7 可忽略 device_ 前缀,让 hash 分布更均匀。
TABLE_SUFFIX --- 表名哈希后缀长度
| 属性 | 值 |
|---|---|
| 默认值 | 0 |
| 取值范围 | [-191, 191] |
| 可否修改 | ❌ |
含义:与 TABLE_PREFIX 类似,但操作表名的后缀。
SINGLE_STABLE --- 单超级表模式
| 属性 | 值 |
|---|---|
| 默认值 | 0 |
| 取值范围 | 0、1 |
| 可否修改 | ❌ |
含义:设为 1 时,该数据库只允许创建一张超级表。可优化某些内部逻辑。
2.2 内存与缓存参数
BUFFER --- 写入缓冲区
| 属性 | 值 |
|---|---|
| 默认值 | 256 MB |
| 取值范围 | [3, 16384] MB |
| 可否修改 | ✅ |
含义:每个 VNode 的内存写入缓冲池大小。数据先写入 MemTable(存放在 BUFFER 中),攒到一定量后刷盘。
内存占用公式:
单数据库总内存 ≈ BUFFER × VGROUPS × REPLICA
示例:BUFFER=256MB, VGROUPS=4, REPLICA=3 → 3072 MB
PAGES --- 元数据缓存页数
| 属性 | 值 |
|---|---|
| 默认值 | 256 |
| 取值范围 | [64, 2147483646] |
| 可否修改 | ✅ |
含义:VNode 元数据引擎(TDB)的内存缓存页数。
内存占用 :PAGES × PAGESIZE × VGROUPS × REPLICA
CACHEMODEL --- 最新数据缓存模式
| 属性 | 值 |
|---|---|
| 默认值 | 'none' |
| 取值范围 | 'none'、'last_row'、'last_value'、'both' |
| 可否修改 | ✅ |
| 模式 | 说明 |
|---|---|
none |
不缓存 |
last_row |
缓存每张子表的最新一行(加速 LAST_ROW() 函数) |
last_value |
缓存每张子表每列最新非 NULL 值(加速 LAST() 函数) |
both |
同时缓存 last_row 和 last_value |
典型使用场景 :监控大屏需要实时显示设备最新状态时,启用 last_row 可将查询延迟从数十毫秒降到亚毫秒。
CACHESIZE --- 最新数据缓存大小
| 属性 | 值 |
|---|---|
| 默认值 | 1 MB |
| 取值范围 | [1, 65536] MB |
| 可否修改 | ✅ |
含义:每个 VNode 用于存放 last_row/last_value 缓存的内存上限。子表数量多时需要相应增大。
2.3 WAL 参数
WAL_LEVEL --- WAL 级别
| 属性 | 值 |
|---|---|
| 默认值 | 1 |
| 取值范围 | 0、1、2 |
| 可否修改 | ✅ |
| 级别 | 行为 | 数据安全 | 写入性能 |
|---|---|---|---|
| 0 | 不写 WAL | 宕机丢数据 | 最高 |
| 1 | 写 WAL,不 fsync | 进程异常不丢,宕机可能丢最后几条 | 高 |
| 2 | 写 WAL + fsync | 宕机也不丢 | 较低(受 fsync 周期影响) |
WAL_FSYNC_PERIOD --- fsync 周期
| 属性 | 值 |
|---|---|
| 默认值 | 3000 ms |
| 取值范围 | [0, 180000] ms |
| 可否修改 | ✅ |
含义:WAL_LEVEL=2 时,操作系统 fsync 的调用周期。设为 0 表示每次写入立即 fsync(最安全但最慢)。
权衡:
- 0 ms:每写必刷,延迟最高但零丢失
- 3000 ms(默认):最多丢失 3 秒数据,写入延迟低
- 越大越快,但宕机时可能丢失数据窗口越大
WAL_RETENTION_PERIOD --- WAL 额外保留时间
| 属性 | 值 |
|---|---|
| 默认值 | 3600 秒 |
| 取值范围 | [-1, ...] |
| 可否修改 | ✅ |
含义:为数据订阅(TMQ)保留的额外 WAL 时间。已提交的 WAL 通常会被截断,但如果有消费者需要回溯,此参数延长 WAL 生命周期。
- -1:不额外保留
- 0:无限保留(注意磁盘空间)
- N > 0:保留 N 秒
WAL_RETENTION_SIZE --- WAL 最大保留大小
| 属性 | 值 |
|---|---|
| 默认值 | 0 |
| 取值范围 | [-1, ...] KB |
| 可否修改 | ✅ |
含义:为数据订阅保留的 WAL 累计大小上限。
- -1:不限制
- 0:不限制(默认)
- N > 0:保留最多 N KB
2.4 副本与高可用参数
REPLICA --- 副本数
| 属性 | 值 |
|---|---|
| 默认值 | 1 |
| 取值范围 | 1、2(企业版)、3 |
| 可否修改 | ✅ |
含义:每个 VGroup 的数据副本数。通过 Raft 共识协议保持副本一致。
| 副本数 | 容忍故障 | 写入开销 | 存储倍数 |
|---|---|---|---|
| 1 | 0 节点 | 本地 WAL | 1× |
| 2 | 1 节点(需仲裁) | 2 个 WAL | 2× |
| 3 | 1 节点(自动选举) | 3 个 WAL + 多数派确认 | 3× |
修改副本数时系统自动执行在线副本变更(参见《1.系统架构 > 06 Raft 共识协议》)。
2.5 Flush 与合并参数
MINROWS --- 数据块最小行数
| 属性 | 值 |
|---|---|
| 默认值 | 100 |
| 取值范围 | [10, 1000000] |
| 可否修改 | ✅ |
含义:内存中每张子表的 MemTable 达到此行数后,该表的数据可参与落盘。
STT_TRIGGER --- 落盘触发阈值
| 属性 | 值 |
|---|---|
| 默认值 | 2 |
| 取值范围 | [1, 16] |
| 可否修改 | ✅ |
含义:当 STT(Sorted String Table,排序落盘文件)文件数量达到此阈值时,触发后台合并(Compaction)。
- 值 = 1:每次落盘直接写入有序数据文件(写入时排序,写放大高)
- 值 > 1:先写 STT 文件,达到阈值后合并(适合高频写入场景)
选择建议:
- 少量子表、高频写入 → STT_TRIGGER = 1(避免 STT 堆积影响查询)
- 海量子表、每表低频 → STT_TRIGGER = 4~8(减少排序开销)
2.6 数据生命周期参数
KEEP --- 数据保留时长
| 属性 | 值 |
|---|---|
| 默认值 | 3650 天 |
| 取值范围 | [1 天, 365000 天],且 KEEP ≥ 3 × DURATION |
| 可否修改 | ✅ |
含义:数据保留时长,超过此时间的数据自动删除。支持三级存储(冷热分离):
sql
-- 三级 KEEP 语法
CREATE DATABASE power KEEP 30d,90d,365d;
-- keep0=30d: 热数据(SSD)
-- keep1=90d: 温数据(HDD)
-- keep2=365d: 冷数据(HDD/S3)
-- 单值 KEEP 语法(三级相同)
CREATE DATABASE power KEEP 365d;
-- 等价于 KEEP 365d,365d,365d
KEEP_TIME_OFFSET --- 过期延迟偏移
| 属性 | 值 |
|---|---|
| 默认值 | 0 |
| 取值范围 | [0, 23] 小时 |
| 可否修改 | ✅ |
含义:数据过期/层级迁移的延迟偏移量(小时),用于将删除/迁移操作推迟到业务低峰期执行。
2.7 S3 对象存储参数(企业版)
S3_KEEPLOCAL --- 本地保留时长
| 属性 | 值 |
|---|---|
| 默认值 | 365 天 |
| 取值范围 | [1 天, 365000 天] |
| 可否修改 | ✅ |
含义:数据在本地磁盘保留的时间,超过后转移到 S3 对象存储。
S3_COMPACT --- S3 压缩合并
| 属性 | 值 |
|---|---|
| 默认值 | 1 |
| 取值范围 | 0、1 |
| 可否修改 | ✅ |
含义:是否对转移到 S3 的数据进行合并压缩。
2.8 加密参数(企业版)
ENCRYPT_ALGORITHM --- 加密算法
| 属性 | 值 |
|---|---|
| 默认值 | 'none' |
| 取值范围 | 'none'、'sm4' |
| 可否修改 | ✅ |
含义:数据库的静态加密(Data at Rest)算法。SM4 为国密算法。
2.9 特殊用途参数
RETENTIONS --- RSMA 降采样策略
| 属性 | 值 |
|---|---|
| 默认值 | 无(不启用 RSMA) |
| 语法 | freq1:keep1,freq2:keep2,... |
| 可否修改 | ❌ |
sql
-- 创建带 RSMA 的数据库
CREATE DATABASE power RETENTIONS 10s:7d,1m:30d,10m:365d;
-- 原始数据保留 7 天
-- 10 秒聚合保留 30 天
-- 10 分钟聚合保留 365 天
启用 RSMA 后,系统自动对写入数据做滚动聚合,无需用户手动创建降采样任务。
SCHEMALESS --- Schemaless 写入模式
| 属性 | 值 |
|---|---|
| 默认值 | 0 |
| 取值范围 | 0、1 |
| 可否修改 | ❌ |
含义:启用 Schemaless(无模式)写入,支持 InfluxDB Line Protocol、OpenTSDB Telnet/JSON 格式自动建表建列。
3. ALTER DATABASE 支持的修改
sql
-- 修改内存缓冲区
ALTER DATABASE power BUFFER 512;
-- 修改副本数
ALTER DATABASE power REPLICA 3;
-- 修改数据保留时长
ALTER DATABASE power KEEP 180d;
-- 修改 WAL 级别
ALTER DATABASE power WAL_LEVEL 2;
-- 修改最新数据缓存
ALTER DATABASE power CACHEMODEL 'both';
ALTER DATABASE power CACHESIZE 16;
-- 修改落盘触发阈值
ALTER DATABASE power STT_TRIGGER 4;
可修改参数完整列表:BUFFER、CACHEMODEL、CACHESIZE、WAL_FSYNC_PERIOD、KEEP、PAGES、REPLICA、WAL_LEVEL、STT_TRIGGER、MINROWS、WAL_RETENTION_PERIOD、WAL_RETENTION_SIZE、S3_KEEPLOCAL、S3_COMPACT、KEEP_TIME_OFFSET、ENCRYPT_ALGORITHM
4. 内部资源分配逻辑
CREATE DATABASE 内部流程:
① 参数校验:检查所有参数是否在合法范围内
② VGroup 分配:
- 将 Hash 全空间 [0, 4294967295] 等分为 N 段
- 为每个 VGroup 选择 REPLICA 个 DNode(负载均衡算法)
- 生成 VGroup 元数据记录
③ MNode 事务:
- 创建分布式事务(重试策略、DB 级冲突检测)
- 通过 Raft 持久化数据库元数据
- 向各 DNode 发送 CreateVnode 请求
④ DNode 执行:
- 在本地文件系统创建 VNode 目录结构
- 初始化 WAL、TSDB、TDB 等存储引擎
- 启动 Raft 实例(如果多副本)
- 返回成功
⑤ 事务提交:
- 所有 DNode 确认成功后,MNode 提交事务
- 数据库状态标记为 READY
- 客户端收到成功响应
代码示例
常用建库场景
sql
-- 场景 1:物联网设备监控(百万子表,3 副本高可用)
CREATE DATABASE iot_monitor
VGROUPS 16
REPLICA 3
PRECISION 'ms'
DURATION 15d
KEEP 180d
BUFFER 256
CACHEMODEL 'last_row'
CACHESIZE 8
STT_TRIGGER 4
WAL_LEVEL 2
WAL_FSYNC_PERIOD 3000;
-- 场景 2:金融交易数据(高精度,低延迟)
CREATE DATABASE trading
VGROUPS 8
REPLICA 3
PRECISION 'us'
DURATION 1d
KEEP 30d
BUFFER 512
COMP 2
WAL_LEVEL 2
WAL_FSYNC_PERIOD 0
CACHEMODEL 'both'
CACHESIZE 32;
-- 场景 3:日志分析(大吞吐,容忍少量丢失)
CREATE DATABASE logs
VGROUPS 32
REPLICA 1
PRECISION 'ms'
DURATION 7d
KEEP 90d
BUFFER 512
WAL_LEVEL 1
STT_TRIGGER 8;
-- 场景 4:带 RSMA 降采样的长期存储
CREATE DATABASE history
VGROUPS 4
PRECISION 'ms'
RETENTIONS 10s:7d,1m:90d,10m:3650d;
查看数据库配置
sql
-- 查看所有数据库
SHOW DATABASES;
-- 查看单个数据库详细参数
SELECT * FROM information_schema.ins_databases WHERE name = 'power';
性能考量
参数对资源的影响
| 参数 | 影响资源 | 计算方式 |
|---|---|---|
| BUFFER | 内存 | BUFFER × VGROUPS × REPLICA |
| PAGES × PAGESIZE | 内存 | PAGES × PAGESIZE × VGROUPS × REPLICA |
| CACHESIZE | 内存 | CACHESIZE × VGROUPS × REPLICA |
| VGROUPS | 线程/文件句柄 | 每个 VGroup 独立线程和文件 |
| REPLICA | 网络/存储 | 数据量 × REPLICA 倍 |
| COMP | CPU vs 存储 | 压缩级别越高 CPU 越高但存储越小 |
容量预估公式
单数据库内存估算:
写入缓冲 = BUFFER × VGROUPS × REPLICA
元数据缓存 = PAGES × PAGESIZE × VGROUPS × REPLICA
Last 缓存 = CACHESIZE × VGROUPS × REPLICA
总内存 ≈ (BUFFER + PAGES×PAGESIZE/1024 + CACHESIZE) × VGROUPS × REPLICA
单数据库磁盘估算:
原始数据/天 = 每秒写入行数 × 86400 × 平均行宽
实际存储/天 = 原始数据/天 ÷ 压缩率(COMP=2 约 5~20 倍)
总存储 = 实际存储/天 × KEEP天数 × REPLICA
FAQ
Q1: VGROUPS 设多少合适?
经验法则:min(CPU核数 × DNode数, 子表数 / 1000)。VGroup 数量决定了写入和查询的最大并行度,但过多会增加调度开销和元数据压力。建议从保守值开始,通过监控写入延迟和 CPU 利用率逐步调整。
Q2: KEEP 可以修改,但 DURATION 不能修改,为什么?
DURATION 决定了数据文件的物理组织方式(每个文件覆盖的时间范围),修改后已有文件的边界无法改变。而 KEEP 只影响过期删除策略------缩短 KEEP 会在下次检查时删除过期文件,延长 KEEP 只是推迟删除。
Q3: WAL_LEVEL = 1 和 WAL_LEVEL = 2 该怎么选?
- 3 副本部署:WAL_LEVEL = 1 通常足够(即使一个节点宕机丢 WAL,还有其他 2 个副本有数据)
- 单副本部署:如果不能接受任何数据丢失 → WAL_LEVEL = 2
- 高吞吐场景且可接受少量丢失 → WAL_LEVEL = 1
Q4: TABLE_PREFIX / TABLE_SUFFIX 什么时候需要设置?
当子表命名有公共前缀(如 factory01_device001、factory01_device002)时,不设置 TABLE_PREFIX 会导致 hash 值集中(因为前缀相同),造成 VGroup 负载不均。设置 TABLE_PREFIX = -10(忽略前 10 字符)可让 hash 只看有区分度的部分。
Q5: STT_TRIGGER 对写入和查询分别有什么影响?
- 写入方面:STT_TRIGGER 越大,落盘时直接写 STT 文件(追加写,快),写入性能越好
- 查询方面:STT_TRIGGER 越大,未合并的 STT 文件越多,查询时需要合并读取的文件越多,查询性能越差
需要在写入吞吐和查询延迟之间权衡。
Q6: 修改 REPLICA 需要多长时间?
取决于数据量。系统需要将全量数据复制到新副本(通过快照传输)。1TB 数据在千兆网络下约需 2-3 小时。修改期间读写不受影响。
参考
系统构架篇
- 01-《TDengine 整体架构全景》
- 02-《集群拓扑深度解析》
- 03-《MNode 内部机制深度解析》
- 04-《RPC 通信层深度解析》
- 05-《VNode 生命周期》
- 06-《RAFT 共识协议》
- 07-《端到端的消息流》
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。