TDengine DECIMAL 数据类型使用手册
1. 概述
DECIMAL
数据类型用来存储高精度数值数据,在其他数据库也被称为 NUMERIC
。DECIMAL
数据类型的基本运算返回的是精确结果,适用于需要精确计算的场景,如金融数据、货币计算等。
相比于浮点数类型(FLOAT、DOUBLE),DECIMAL
类型:
- 优势:保证精确计算,避免浮点数舍入误差
- 劣势:计算性能相对较低
2. 基本概念
2.1 核心术语
DECIMAL
数据类型中有两个重要术语:
- Precision(精度):指整个数值中有效数字个数,包括小数点左右两侧的所有数字。
PRECISION
最大值为MAX_PRECISION
。 - Scale(标度):指位于小数点右侧的小数个数,必须为非负整数。
SCALE
必须小于等于指定的PRECISION
值,且SCALE
最大值为MAX_SCALE
。
2.2 定义示例
定义一个 DECIMAL(4,2)
数据类型:
- 有效数字最多为 4 个
- 小数点右侧 2 位
- 表示的值范围为:
[-99.99, 99.99]
2.3 约束限制
- 不支持
DECIMAL UNSIGNED
- 只在 Linux、Mac、Windows 平台支持
MAX_PRECISION
值为38
,MAX_SCALE
值也为38
(采用 ClickHouse 中 Decimal128 相同行为)
3. 语法定义
3.1 基本语法
DECIMAL(precision, scale) -- 完整格式
DECIMAL(precision) -- scale 默认为 0
3.2 参数说明
precision
:必须为正整数,取值范围[1, MAX_PRECISION]
scale
:必须为非负整数,取值范围[0, min(MAX_SCALE, precision)]
- 不指定
scale
时,默认为 0,即只表示整数 - 若
precision
等于scale
,则只能表示(-1,1)
范围内的值
3.3 示例
-- 创建表使用 DECIMAL 类型
CREATE TABLE financial_data (
ts TIMESTAMP,
amount DECIMAL(10,2), -- 10位精度,2位小数
rate DECIMAL(5,4), -- 5位精度,4位小数
count DECIMAL(8) -- 8位精度,0位小数(整数)
);
3.4 存储规则
- 根据数据大小自动选择
Decimal64
或Decimal128
进行存储 Decimal64
:8字节,最大精度18位Decimal128
:16字节,最大精度38位
注意:不支持 precision
和 scale
都不指定的方式定义 DECIMAL 类型。
4. 数据操作
4.1 插入数据
DECIMAL 类型数据可以通过多种方式插入:
4.1.1 数值格式插入
-- 插入数值,不会降低精度
INSERT INTO financial_data VALUES (NOW(), 123.45, 0.1250, 1000);
4.1.2 字符串格式插入
-- 插入字符串格式的数值
INSERT INTO financial_data VALUES (NOW(), '999.99', '0.9999', '99999999');
4.1.3 科学计数法插入
-- 支持科学计数法,形如 1E-37 即 1×10^(-37)
INSERT INTO financial_data VALUES (NOW(), 1.23E2, 1.5e-3, 1E6);
4.2 数据精度处理
4.2.1 精度截断
当插入数值的 scale
高于列定义的 scale
时,会进行四舍五入:
-- 列定义为 DECIMAL(3,1)
INSERT INTO test_table VALUES (0.11); -- 实际存储为 0.1
4.2.2 溢出检查
当插入的数值超出精度范围时,会报 Decimal field overflow
错误:
-- 列定义为 DECIMAL(3,1),有效范围 [-99.9, 99.9]
INSERT INTO test_table VALUES (100.1); -- 报错:Decimal field overflow
4.3 查询显示
查询结果的显示格式受 DECIMAL 的 PRECISION
和 SCALE
控制:
-- 对于 DECIMAL(5,2) 列
SELECT amount FROM financial_data; -- 值 2.3 显示为 2.30
5. 表达式计算
5.1 常量处理
查询中的数值常量使用整数或 DOUBLE 类型解释,不会自动解释为 DECIMAL 类型。如需使用 DECIMAL 类型,可以手动进行类型转换:
-- 常量被解释为 DOUBLE
SELECT 3.14159 + amount FROM financial_data;
-- 手动转换为 DECIMAL
SELECT CAST(3.14159 AS DECIMAL(10,5)) + amount FROM financial_data;
5.2 运算规则
5.2.1 基本运算
DECIMAL 类型支持的基本运算符:+
、-
、*
、/
、%
、>
、>=
、<
、<=
、=
、!=
5.2.2 运算结果类型
运算类型 | 运算符 | 输出类型 | Scale 规则 |
---|---|---|---|
decimal + decimal | + | DECIMAL | max(S1, S2) |
decimal - decimal | - | DECIMAL | max(S1, S2) |
decimal * decimal | * | DECIMAL | MIN(MAX_SCALE, S1 + S2) |
decimal / decimal | / | DECIMAL | S1 |
decimal op float/double | +,-,*,/ | DOUBLE | - |
decimal op integer | +,-,*,/ | DECIMAL | - |
5.3 比较运算
DECIMAL 类型作为数值类型,在与其他数值类型比较时,遵循数值比较规则:
-- 以下比较结果为 true
SELECT 1.1000::DECIMAL(5,4) = 1.1::DECIMAL(3,1); -- DECIMAL 之间
SELECT 123::DECIMAL(3,0) = 123; -- DECIMAL 与整数
SELECT 1.11::DECIMAL(3,2) = 1.11::FLOAT; -- DECIMAL 与浮点数
5.4 溢出处理
- 若计算结果值大于
MAX_PRECISION
时可表示的最大值,则报overflow
错误 - 若计算结果未溢出,但小数点左侧位数大于
MAX_PRECISION - SCALE
,则自动截断,减小SCALE
5.5 类型转换规则
操作符两侧不同类型字段计算时的转换规则:
源类型 | 目标类型 | 说明 |
---|---|---|
NULL | NULL | 保持 NULL |
BOOL/TINYINT/SMALLINT/INT/BIGINT | DECIMAL | 整数类型转换为 DECIMAL |
UTINYINT/USMALLINT/UINT/UBIGINT | DECIMAL | 无符号整数转换为 DECIMAL |
FLOAT/DOUBLE | DOUBLE | 浮点数运算结果为 DOUBLE |
VARCHAR/TIMESTAMP | DECIMAL | 字符串和时间戳转换为 DECIMAL |
NCHAR/BINARY | DOUBLE | 转换为 DOUBLE |
JSON/VARBINARY/GEOMETRY | 错误 | 不支持转换 |
6. 函数支持
6.1 函数返回类型
DECIMAL 类型支持的函数及其返回类型:
6.1.1 数学函数
函数 | 返回类型 | 说明 |
---|---|---|
ABS(decimal) | DECIMAL | 绝对值 |
ROUND(decimal) | DECIMAL | 四舍五入 |
FLOOR(decimal) | DECIMAL | 向下取整 |
CEIL(decimal) | BIGINT | 向上取整 |
ACOS/ASIN/ATAN/COS/SIN/TAN | DOUBLE | 三角函数 |
LOG/POW/SQRT | DOUBLE | 对数、幂、平方根 |
6.1.2 聚合函数
函数 | 返回类型 | 说明 |
---|---|---|
SUM(decimal) | DECIMAL | 求和 |
AVG(decimal) | DECIMAL | 平均值 |
MAX(decimal) | DECIMAL | 最大值 |
MIN(decimal) | DECIMAL | 最小值 |
COUNT(decimal) | BIGINT | 计数 |
6.1.3 窗口函数
函数 | 返回类型 | 说明 |
---|---|---|
FIRST(decimal) | DECIMAL | 首个值 |
LAST(decimal) | DECIMAL | 最后值 |
APERCENTILE(decimal, p) | DECIMAL | 百分位数 |
PERCENTILE(decimal, p) | DECIMAL | 百分位数 |
SPREAD(decimal) | DECIMAL | 极差 |
6.1.4 时间序列函数
函数 | 返回类型 | 说明 |
---|---|---|
CSUM(decimal) | DECIMAL | 累积和 |
DERIVATIVE(decimal) | DECIMAL | 导数 |
DIFF(decimal) | DECIMAL | 差分 |
MAVG(decimal, k) | DECIMAL | 移动平均 |
IRATE(decimal) | DOUBLE | 瞬时速率 |
TWA(decimal) | DOUBLE | 时间加权平均 |
6.1.5 统计函数
函数 | 返回类型 | 说明 |
---|---|---|
STDDEV(decimal) | DOUBLE | 标准差 |
HISTOGRAM(decimal, bins) | DOUBLE/BIGINT | 直方图 |
HYPERLOGLOG(decimal) | INTEGER | 基数估计 |
6.2 类型转换函数
-- CAST 函数支持
SELECT CAST(123.456 AS DECIMAL(10,2)); -- 结果: 123.46
SELECT CAST('999.99' AS DECIMAL(8,2)); -- 结果: 999.99
SELECT CAST(column1 AS DECIMAL(15,4)) FROM t1; -- 类型转换
7. 使用示例
7.1 创建表和插入数据
-- 创建包含 DECIMAL 类型的表
CREATE TABLE finance_records (
ts TIMESTAMP,
account_id INT,
amount DECIMAL(15,2), -- 金额:15位精度,2位小数
rate DECIMAL(8,6), -- 利率:8位精度,6位小数
balance DECIMAL(20,2), -- 余额:20位精度,2位小数
quantity DECIMAL(10,0) -- 数量:10位精度,0位小数(整数)
);
-- 插入数据
INSERT INTO finance_records VALUES
(NOW(), 1001, 1234.56, 0.025000, 10000.00, 100),
(NOW(), 1002, 2345.67, 0.030000, 25000.00, 200),
(NOW(), 1003, 3456.78, 0.035000, 50000.00, 300);
7.2 查询计算示例
-- 基本查询
SELECT account_id, amount, rate, balance FROM finance_records;
-- 计算利息
SELECT
account_id,
amount,
rate,
amount * rate AS interest,
balance + amount * rate AS new_balance
FROM finance_records;
-- 聚合统计
SELECT
SUM(amount) AS total_amount,
AVG(rate) AS avg_rate,
MAX(balance) AS max_balance,
MIN(balance) AS min_balance
FROM finance_records;
-- 条件查询
SELECT * FROM finance_records
WHERE amount > 2000.00 AND rate >= 0.030000;
7.3 精度控制示例
-- 创建不同精度的表
CREATE TABLE precision_test (
ts TIMESTAMP,
small_decimal DECIMAL(5,2), -- 范围:-999.99 to 999.99
medium_decimal DECIMAL(10,4), -- 范围:-999999.9999 to 999999.9999
large_decimal DECIMAL(18,6) -- 范围:-999999999999.999999 to 999999999999.999999
);
-- 插入测试数据
INSERT INTO precision_test VALUES
(NOW(), 123.45, 1234.5678, 123456789.123456),
(NOW(), 999.99, 999999.9999, 999999999999.999999);
-- 精度截断示例
INSERT INTO precision_test VALUES
(NOW(), 123.456, 1234.56789, 123456789.1234567);
-- 实际存储为:123.46, 1234.5679, 123456789.123457(四舍五入)
7.4 类型转换示例
-- 字符串转 DECIMAL
SELECT CAST('12345.67' AS DECIMAL(10,2)) AS decimal_value;
-- 整数转 DECIMAL
SELECT CAST(12345 AS DECIMAL(10,2)) AS decimal_value;
-- DECIMAL 转字符串
SELECT CAST(amount AS VARCHAR(20)) AS amount_str FROM finance_records;
-- 混合类型计算
SELECT
amount,
CAST(amount AS FLOAT) AS amount_float,
amount + 100 AS amount_plus_int,
amount * 1.1 AS amount_times_float -- 结果为 DOUBLE
FROM finance_records;
8. 客户端和API支持
8.1 C API
8.1.1 查询结果处理
使用 C API 的 taos_fetch_row
查询 DECIMAL 类型数据时,该列数据会被转换为字符串类型返回:
// 查询 DECIMAL 类型数据
TAOS_RES *res = taos_query(taos, "SELECT amount FROM finance_records");
TAOS_ROW row;
while ((row = taos_fetch_row(res)) != NULL) {
// DECIMAL 列作为字符串读取
char *amount_str = (char *)row[0];
printf("Amount: %s\n", amount_str);
}
8.1.2 Raw Block 解析
调用 taos_fetch_raw_block
接口时,Raw Block 内结构保持不变:
DECIMAL64
:8字节定长字段DECIMAL128
:16字节定长字段- Schema 信息存储格式:
字段 | 长度 | 说明 |
---|---|---|
bytes | 1字节 | 所需大小(8/16) |
empty | 1字节 | 保留字段 |
precision | 1字节 | 精度值 |
scale | 1字节 | 标度值 |
8.1.3 解析 DECIMAL 数据
Decimal64 解析:
// 8字节数据转换为 int64_t
int64_t decimal64_value = *(int64_t*)data;
// 根据 scale 计算实际值
double actual_value = (double)decimal64_value / pow(10, scale);
Decimal128 解析:
// 16字节数据转换为 int128(小端序)
// 需要自定义 int128 处理或使用库函数
// 根据 scale 计算实际值
8.2 连接器支持
各语言连接器对 DECIMAL 类型的支持:
连接器 | 支持状态 | 返回类型 | 说明 |
---|---|---|---|
Java | 支持 | BigDecimal | 完整精度支持 |
Python | 支持 | Decimal | 使用 decimal 模块 |
Go | 支持 | string | 字符串形式返回 |
Node.js | 支持 | string | 字符串形式返回 |
C# | 支持 | decimal | .NET Decimal 类型 |
Rust | 支持 | string | 字符串形式返回 |
8.3 工具支持
8.3.1 taos Shell
# 查看表结构
taos> DESC finance_records;
# 输出示例:
# amount | DECIMAL(15,2) | ...
# 查询数据
taos> SELECT amount FROM finance_records;
# 输出格式按照 DECIMAL 定义的精度显示
8.3.2 taosBenchmark
taosBenchmark 支持 DECIMAL 类型的性能测试:
# 创建包含 DECIMAL 类型的测试表
taosbenchmark -P 6030 -d test_db -t 10 -n 100000 \
--columns "amount DECIMAL(15,2),rate DECIMAL(8,6)"
9. 性能特性
9.1 性能对比
DECIMAL 类型相比于其他数值类型的性能特性:
操作类型 | DECIMAL | INT/BIGINT | FLOAT/DOUBLE | 性能比较 |
---|---|---|---|---|
插入 | 正常 | 最快 | 快 | DECIMAL < FLOAT < INT |
查询 | 正常 | 最快 | 快 | DECIMAL < FLOAT < INT |
运算 | 慢 | 最快 | 快 | DECIMAL 比其他类型慢 30-50% |
聚合 | 慢 | 最快 | 快 | DECIMAL 比其他类型慢 30-50% |
9.2 存储优化
- 压缩算法:DECIMAL 类型提供专门的压缩算法
- 存储格式:根据精度自动选择 Decimal64 或 Decimal128
- 内存使用:相比字符串存储数值更节省空间
9.3 计算优化
- 批量计算:支持向量化计算,提高批量处理性能
- 缓存优化:频繁使用的精度信息进行缓存
- 并行计算:支持多线程并行处理
10. 使用场景
10.1 适用场景
DECIMAL 类型特别适合以下场景:
金融系统
- 货币计算
- 利率计算
- 财务报表
- 交易记录
科学计算
- 精确测量数据
- 统计分析
- 实验数据记录
商业应用
- 价格计算
- 税务计算
- 库存管理
- 成本分析
10.2 典型应用
-- 金融应用示例
CREATE TABLE account_transactions (
ts TIMESTAMP,
account_id BIGINT,
transaction_type VARCHAR(20),
amount DECIMAL(18,2), -- 交易金额
balance DECIMAL(20,2), -- 账户余额
exchange_rate DECIMAL(10,6), -- 汇率
fee DECIMAL(8,4) -- 手续费
);
-- 科学数据示例
CREATE TABLE sensor_data (
ts TIMESTAMP,
sensor_id INT,
temperature DECIMAL(6,3), -- 温度(精确到千分位)
pressure DECIMAL(8,2), -- 压力
humidity DECIMAL(5,2), -- 湿度
coordinate_x DECIMAL(15,8), -- 坐标(高精度)
coordinate_y DECIMAL(15,8)
);
10.3 不适用场景
以下场景不建议使用 DECIMAL 类型:
- 高频交易:对性能要求极高的场景
- 简单计数:整数计数场景直接使用 INT/BIGINT
- 近似计算:不需要精确计算的场景可使用 FLOAT/DOUBLE
- 日志数据:大量日志数据建议使用性能更好的类型
11. 约束与限制
11.1 系统约束
- 平台支持:仅支持 Linux、macOS、Windows 平台
- 精度限制:
MAX_PRECISION = 38
(最大精度)MAX_SCALE = 38
(最大标度)SCALE ≤ PRECISION
(标度不能超过精度)
11.2 功能限制
11.2.1 当前不支持的功能
- 标签列:DECIMAL 类型不能用作标签列
- Schema 修改:不支持修改 DECIMAL 类型的
precision
和scale
- Schemaless 写入:暂不支持无模式写入 DECIMAL 数据
- Stmt 参数绑定:暂不支持预处理语句参数绑定
11.2.2 部分支持的功能
- UDF 支持:用户定义函数对 DECIMAL 类型支持有限
- 数学函数:部分高级数学函数(如对数、三角函数等)返回 DOUBLE 类型
11.3 兼容性约束
- 版本兼容:创建 DECIMAL 类型后不能回退到不支持 DECIMAL 的版本
- 组件兼容:
- 流计算:支持
- 数据订阅:支持,需要类型转换
- SMA 索引:需要重新计算
- 连续查询:支持
11.4 性能约束
- 计算性能:比 INT/FLOAT 类型慢 30-50%
- 存储开销:比对应的整数类型占用更多空间
- 内存使用:计算过程中需要更多内存
11.5 数据范围约束
根据精度和标度的不同,DECIMAL 类型的数值范围如下:
精度 | 标度 | 数值范围示例 |
---|---|---|
DECIMAL(3,0) | 0 | -999 to 999 |
DECIMAL(3,1) | 1 | -99.9 to 99.9 |
DECIMAL(5,2) | 2 | -999.99 to 999.99 |
DECIMAL(10,4) | 4 | -999999.9999 to 999999.9999 |
DECIMAL(18,6) | 6 | -999999999999.999999 to 999999999999.999999 |
12. 故障排除
12.1 常见错误
12.1.1 精度溢出错误
-- 错误示例
CREATE TABLE test (id INT, amount DECIMAL(5,2));
INSERT INTO test VALUES (1, 12345.67); -- 错误:Decimal field overflow
解决方案:增加精度或减少数值大小
12.1.2 类型转换错误
-- 错误示例
SELECT amount + 'abc' FROM test; -- 错误:Invalid type conversion
解决方案:确保参与运算的数据类型兼容
12.1.3 精度定义错误
-- 错误示例
CREATE TABLE test (amount DECIMAL(5,6)); -- 错误:Scale 不能大于 Precision
解决方案:确保 scale ≤ precision
12.2 性能问题
12.2.1 计算性能慢
问题:DECIMAL 类型计算比其他数值类型慢
解决方案:
- 评估是否真的需要 DECIMAL 精度
- 考虑使用 BIGINT 存储整数部分,必要时转换
- 批量计算时考虑使用更高效的数据类型
12.2.2 查询性能优化
建议:
- 对 DECIMAL 列创建适当的索引
- 避免在 WHERE 子句中对 DECIMAL 列进行复杂计算
- 使用批量插入提高写入性能
12.3 数据一致性
12.3.1 精度损失问题
问题:插入时精度超出定义范围
解决方案:
- 检查输入数据的精度
- 适当调整 DECIMAL 类型的精度定义
- 在应用层进行数据验证
13. 最佳实践
13.1 设计建议
- 合理选择精度:根据业务需求选择合适的精度,避免过度设计
- 统一精度标准:同一业务域的 DECIMAL 类型保持一致的精度
- 考虑性能影响:在性能敏感的场景中谨慎使用 DECIMAL 类型
- 数据验证:在应用层对 DECIMAL 数据进行有效性验证
13.2 使用建议
- 金融数据:推荐使用 DECIMAL(18,2) 或 DECIMAL(20,2)
- 比率数据:推荐使用 DECIMAL(8,6) 或 DECIMAL(10,6)
- 测量数据:根据测量精度选择合适的标度
- 计算结果:考虑中间计算结果的精度需求
13.3 运维建议
- 监控性能:定期监控 DECIMAL 类型相关查询的性能
- 存储规划:考虑 DECIMAL 类型对存储空间的影响
- 备份策略:确保备份恢复过程中 DECIMAL 数据的完整性
- 版本升级:升级前确认 DECIMAL 类型的兼容性
14. 参考信息
14.1 相关文档
- TDengine 数据类型文档
- TDengine SQL 参考手册
- TDengine 连接器文档
- TDengine 性能优化指南
14.2 版本支持
- v3.3.6.0:引入 DECIMAL 类型支持
14.3 技术支持
如遇到 DECIMAL 类型相关问题,请:
- 查阅官方文档
- 在 TDengine 社区论坛提问
- 联系技术支持团队
- 提交 GitHub Issues