TDengine BLOB 数据类型用户手册
1. 概述
1.1 功能背景
BLOB (Binary Large Object) 数据类型是 TDengine 为解决车联网、航空等特殊场景下大容量二进制数据存储需求而设计的新数据类型。针对以下问题进行优化:
- 数据容量限制:车联网、航空场景的原始数据报文通常大于 100 KB,而TDengine的Binary类型仅支持 64 KB
- 写入性能问题:多表低频时,二进制数据在落盘前只能缓存在内存中,反复合并造成写入性能下降明显
- 存储效率:需要一种专门的存储引擎来处理大容量二进制数据
1.2 功能特性
BLOB 类型提供以下核心特性:
- 大容量存储:支持最大 4 MB 的二进制数据存储
- 高性能写入:采用独立的 BSE 存储引擎,显著提升写入性能
- 灵活数据格式:支持未解析/拆分行列的二进制或文本型数据
- 多种写入方式:支持 SQL 语句写入和参数绑定写入
2. 数据类型定义
2.1 类型声明
-- BLOB数据类型定义
BLOB -- 最大长度4MB的二进制数据类型
2.2 类型标识
在 TDengine 客户端代码中,BLOB 类型对应的标识符为:
#define TSDB_DATA_TYPE_BLOB 18 // 主要BLOB类型
2.3 存储限制
#define TSDB_MAX_BLOB_LEN (4 << 20) // 4MB = 4,194,304 bytes
3. 表结构设计
3.1 基本语法
CREATE TABLE table_name (
ts TIMESTAMP, -- 主键时间戳
data BLOB, -- BLOB数据列
other_column_type, -- 其他数据类型列
...
);
3.2 创建示例
-- 车联网数据表
CREATE TABLE vehicle_data (
ts TIMESTAMP,
vehicle_id NCHAR(20),
raw_data BLOB, -- 存储原始CAN总线数据
device_status BLOB -- 存储设备状态信息
);
-- 航空数据表
CREATE TABLE flight_data (
ts TIMESTAMP,
flight_id NCHAR(10),
radar_data BLOB, -- 雷达原始数据
sensor_data BLOB -- 传感器数据包
);
-- 物联网设备表
CREATE TABLE iot_devices (
ts TIMESTAMP,
device_id NCHAR(32),
config_data BLOB, -- 设备配置信息
log_data BLOB -- 设备运行日志
);
4. 数据写入
4.1 SQL 语句写入
4.1.1 十六进制格式写入
-- 使用\x前缀的十六进制格式
INSERT INTO vehicle_data VALUES (
NOW,
'VH001',
'\x48656c6c6f20576f726c64', -- "Hello World"的十六进制表示
'\x010203040506070809'
);
-- 批量插入
INSERT INTO vehicle_data VALUES
(NOW, 'VH001', '\x48656c6c6f', '\x010203'),
(NOW+1s, 'VH002', '\x576f726c64', '\x040506'),
(NOW+2s, 'VH003', '\x54444442', '\x070809');
4.1.2 文本数据写入
-- 直接写入文本数据(会自动转换为二进制)
INSERT INTO flight_data VALUES (
NOW,
'FL001',
'Binary data content here',
'Status: Active, Altitude: 35000'
);
4.2 参数绑定写入
4.2.1 使用STMT接口
#include "taos.h"
int write_blob_data_stmt() {
TAOS *taos = taos_connect("localhost", "root", "taosdata", "test", 0);
if (taos == NULL) {
printf("连接失败\n");
return -1;
}
// 准备SQL语句
TAOS_STMT *stmt = taos_stmt_init(taos);
const char *sql = "INSERT INTO vehicle_data VALUES (?, ?, ?, ?)";
if (taos_stmt_prepare(stmt, sql, 0) != 0) {
printf("prepare失败: %s\n", taos_stmt_errstr(stmt));
return -1;
}
// 准备BLOB数据
char blob_data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
int64_t ts = 1640995200000; // 时间戳
char vehicle_id[] = "VH001";
// 绑定参数
TAOS_MULTI_BIND params[4];
// 时间戳参数
params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP;
params[0].buffer = &ts;
params[0].buffer_length = sizeof(ts);
params[0].length = ¶ms[0].buffer_length;
params[0].is_null = NULL;
params[0].num = 1;
// 车辆ID参数
params[1].buffer_type = TSDB_DATA_TYPE_NCHAR;
params[1].buffer = vehicle_id;
params[1].buffer_length = strlen(vehicle_id);
params[1].length = ¶ms[1].buffer_length;
params[1].is_null = NULL;
params[1].num = 1;
// BLOB数据参数
params[2].buffer_type = TSDB_DATA_TYPE_BLOB;
params[2].buffer = blob_data;
params[2].buffer_length = sizeof(blob_data);
params[2].length = ¶ms[2].buffer_length;
params[2].is_null = NULL;
params[2].num = 1;
// 第二个BLOB参数
params[3].buffer_type = TSDB_DATA_TYPE_BLOB;
params[3].buffer = blob_data;
params[3].buffer_length = sizeof(blob_data);
params[3].length = ¶ms[3].buffer_length;
params[3].is_null = NULL;
params[3].num = 1;
// 绑定并执行
if (taos_stmt_bind_param(stmt, params) != 0) {
printf("bind失败: %s\n", taos_stmt_errstr(stmt));
return -1;
}
if (taos_stmt_add_batch(stmt) != 0) {
printf("add_batch失败: %s\n", taos_stmt_errstr(stmt));
return -1;
}
if (taos_stmt_execute(stmt) != 0) {
printf("execute失败: %s\n", taos_stmt_errstr(stmt));
return -1;
}
printf("BLOB数据写入成功\n");
taos_stmt_close(stmt);
taos_close(taos);
return 0;
}
4.2.2 使用 STMT2 接口
#include "taos.h"
int write_blob_data_stmt2() {
TAOS *taos = taos_connect("localhost", "root", "taosdata", "test", 0);
if (taos == NULL) {
printf("连接失败\n");
return -1;
}
// 创建STMT2实例
TAOS_STMT2_OPTION option = {0};
TAOS_STMT2 *stmt = taos_stmt2_init(taos, &option);
const char *sql = "INSERT INTO ? VALUES (?, ?, ?, ?)";
if (taos_stmt2_prepare(stmt, sql, 0) != 0) {
printf("prepare失败: %s\n", taos_stmt2_error(stmt));
return -1;
}
// 设置表名
TAOS_STMT2_BINDV table_name;
table_name.buffer = "vehicle_data";
table_name.length = strlen("vehicle_data");
table_name.buffer_type = TSDB_DATA_TYPE_BINARY;
table_name.is_null = NULL;
// 准备数据
int64_t ts = 1640995200000;
char vehicle_id[] = "VH001";
char blob_data[] = {0x01, 0x02, 0x03, 0x04, 0x05};
char status_data[] = {0xFF, 0xFE, 0xFD, 0xFC};
// 绑定时间戳
TAOS_STMT2_BINDV ts_bind;
ts_bind.buffer = &ts;
ts_bind.length = sizeof(ts);
ts_bind.buffer_type = TSDB_DATA_TYPE_TIMESTAMP;
ts_bind.is_null = NULL;
// 绑定车辆ID
TAOS_STMT2_BINDV id_bind;
id_bind.buffer = vehicle_id;
id_bind.length = strlen(vehicle_id);
id_bind.buffer_type = TSDB_DATA_TYPE_NCHAR;
id_bind.is_null = NULL;
// 绑定BLOB数据
TAOS_STMT2_BINDV blob_bind;
blob_bind.buffer = blob_data;
blob_bind.length = sizeof(blob_data);
blob_bind.buffer_type = TSDB_DATA_TYPE_BLOB;
blob_bind.is_null = NULL;
// 绑定状态数据
TAOS_STMT2_BINDV status_bind;
status_bind.buffer = status_data;
status_bind.length = sizeof(status_data);
status_bind.buffer_type = TSDB_DATA_TYPE_BLOB;
status_bind.is_null = NULL;
// 执行绑定
taos_stmt2_bind_param(stmt, &ts_bind, 0);
taos_stmt2_bind_param(stmt, &id_bind, 1);
taos_stmt2_bind_param(stmt, &blob_bind, 2);
taos_stmt2_bind_param(stmt, &status_bind, 3);
// 执行插入
int affected_rows;
if (taos_stmt2_exec(stmt, &affected_rows) != 0) {
printf("执行失败: %s\n", taos_stmt2_error(stmt));
return -1;
}
printf("STMT2插入成功,影响行数: %d\n", affected_rows);
taos_stmt2_close(stmt);
taos_close(taos);
return 0;
}
4.3 批量写入示例
// 批量写入大量BLOB数据
int batch_write_blob_data() {
TAOS *taos = taos_connect("localhost", "root", "taosdata", "test", 0);
TAOS_STMT *stmt = taos_stmt_init(taos);
const char *sql = "INSERT INTO vehicle_data VALUES (?, ?, ?, ?)";
taos_stmt_prepare(stmt, sql, 0);
const int BATCH_SIZE = 1000;
for (int i = 0; i < BATCH_SIZE; i++) {
// 生成测试数据
int64_t ts = 1640995200000 + i * 1000; // 每秒一条
char vehicle_id[32];
snprintf(vehicle_id, sizeof(vehicle_id), "VH%06d", i);
// 生成BLOB数据(模拟CAN总线数据)
char blob_data[1024];
for (int j = 0; j < sizeof(blob_data); j++) {
blob_data[j] = (char)(i + j) % 256;
}
// 绑定参数并添加到批次
TAOS_MULTI_BIND params[4];
// ... 设置参数 ...
taos_stmt_bind_param(stmt, params);
taos_stmt_add_batch(stmt);
// 每100条执行一次
if ((i + 1) % 100 == 0) {
taos_stmt_execute(stmt);
}
}
// 执行剩余数据
taos_stmt_execute(stmt);
taos_stmt_close(stmt);
taos_close(taos);
return 0;
}
5. 数据查询
5.1 基本查询
-- 查询所有BLOB数据
SELECT ts, vehicle_id, raw_data, device_status FROM vehicle_data;
-- 投影查询
SELECT ts, vehicle_id FROM vehicle_data WHERE ts > NOW - 1h;
-- 条件查询(BLOB字段支持NULL判断)
SELECT * FROM vehicle_data WHERE raw_data IS NOT NULL;
-- 排除空BLOB数据
SELECT * FROM vehicle_data WHERE raw_data IS NOT NULL AND device_status IS NOT NULL;
5.2 聚合查询
-- 统计BLOB数据条数
SELECT COUNT(*) FROM vehicle_data WHERE raw_data IS NOT NULL;
-- 按时间分组统计
SELECT COUNT(*), LAST(vehicle_id) FROM vehicle_data
WHERE ts >= '2024-01-01 00:00:00'
GROUP BY INTERVAL(1h);
-- 多表联合查询
SELECT v.ts, v.vehicle_id, v.raw_data, f.radar_data
FROM vehicle_data v, flight_data f
WHERE v.ts = f.ts;
5.3 UNION ALL 查询
-- 合并多表的BLOB数据
SELECT ts, 'vehicle' as source, raw_data as data_blob FROM vehicle_data
UNION ALL
SELECT ts, 'flight' as source, radar_data as data_blob FROM flight_data
ORDER BY ts;
5.4 函数支持
BLOB 类型支持与 VARCHAR 相同的函数:
-- 长度函数(返回字节长度)
SELECT LENGTH(raw_data) FROM vehicle_data;
-- 字符串函数(如果BLOB包含文本数据)
SELECT SUBSTRING(raw_data, 1, 10) FROM vehicle_data;
-- 空值处理
SELECT COALESCE(raw_data, '\x00') FROM vehicle_data;
6. 数据读取与处理
6.1 C 语言读取示例
#include "taos.h"
#include <stdio.h>
#include <stdlib.h>
int read_blob_data() {
TAOS *taos = taos_connect("localhost", "root", "taosdata", "test", 0);
if (taos == NULL) {
printf("连接失败\n");
return -1;
}
TAOS_RES *result = taos_query(taos, "SELECT ts, vehicle_id, raw_data FROM vehicle_data LIMIT 10");
if (taos_errno(result) != 0) {
printf("查询失败: %s\n", taos_errstr(result));
taos_free_result(result);
taos_close(taos);
return -1;
}
TAOS_FIELD *fields = taos_fetch_fields(result);
int field_count = taos_field_count(result);
printf("字段信息:\n");
for (int i = 0; i < field_count; i++) {
printf("字段%d: %s, 类型: %d, 长度: %d\n",
i, fields[i].name, fields[i].type, fields[i].bytes);
}
TAOS_ROW row;
while ((row = taos_fetch_row(result)) != NULL) {
int *lengths = taos_fetch_lengths(result);
// 处理时间戳
if (row[0] != NULL) {
int64_t ts = *(int64_t*)row[0];
printf("时间戳: %lld\n", ts);
}
// 处理车辆ID
if (row[1] != NULL) {
printf("车辆ID: %.*s\n", lengths[1], (char*)row[1]);
}
// 处理BLOB数据
if (row[2] != NULL) {
printf("BLOB数据长度: %d字节\n", lengths[2]);
printf("BLOB数据(十六进制): ");
// 显示前20个字节
int display_len = lengths[2] > 20 ? 20 : lengths[2];
for (int i = 0; i < display_len; i++) {
printf("%02X ", (unsigned char)((char*)row[2])[i]);
}
if (lengths[2] > 20) {
printf("...");
}
printf("\n");
}
printf("---\n");
}
taos_free_result(result);
taos_close(taos);
return 0;
}
// 十六进制转 ASCII 工具函数
void hex_to_ascii(const char* hex_data, int hex_len, char* ascii_buffer, int buffer_size) {
int ascii_len = 0;
for (int i = 0; i < hex_len && ascii_len < buffer_size - 1; i++) {
ascii_len += snprintf(ascii_buffer + ascii_len, buffer_size - ascii_len,
"%02X", (unsigned char)hex_data[i]);
}
ascii_buffer[ascii_len] = '\0';
}
6.2 数据格式转换
// BLOB数据转换工具函数
int process_blob_data(const char* blob_data, int blob_len) {
printf("处理BLOB数据, 长度: %d字节\n", blob_len);
// 检查是否为文本数据
bool is_text = true;
for (int i = 0; i < blob_len; i++) {
if (blob_data[i] < 32 || blob_data[i] > 126) {
if (blob_data[i] != '\n' && blob_data[i] != '\r' && blob_data[i] != '\t') {
is_text = false;
break;
}
}
}
if (is_text) {
printf("文本内容: %.*s\n", blob_len, blob_data);
} else {
printf("二进制数据,前32字节十六进制: ");
int display_len = blob_len > 32 ? 32 : blob_len;
for (int i = 0; i < display_len; i++) {
printf("%02X ", (unsigned char)blob_data[i]);
}
printf("\n");
}
return 0;
}
7. 性能优化
7.1 写入性能对比
根据官方测试数据,BLOB类型 相比 Binary 类型数据的写入性能提升显著:
数据长度 | 128B | 512B | 2KB | 8KB | 32KB |
---|---|---|---|---|---|
相比 Binary 的速度提升 | 73% | 101% | 223% | 347% | 409% |
测试环境:VGroup = 2,每个 VGroup 子表10000,Buffer 256MB
7.2 性能优化建议
7.2.1 批量写入
-- 建议使用批量插入而非单条插入
INSERT INTO vehicle_data VALUES
(NOW, 'VH001', '\x48656c6c6f', '\x010203'),
(NOW+1s, 'VH002', '\x576f726c64', '\x040506'),
(NOW+2s, 'VH003', '\x54444442', '\x070809'),
-- 更多数据...
(NOW+999s, 'VH999', '\x454e4420', '\xFFFFFF');
7.2.2 使用参数绑定
// 推荐:使用参数绑定进行批量插入
TAOS_STMT *stmt = taos_stmt_init(taos);
taos_stmt_prepare(stmt, "INSERT INTO vehicle_data VALUES (?, ?, ?, ?)", 0);
// 循环绑定和执行
for (int i = 0; i < batch_size; i++) {
taos_stmt_bind_param(stmt, params);
taos_stmt_add_batch(stmt);
}
taos_stmt_execute(stmt);
7.2.3 合理设置缓冲区
// 在连接时设置合适的缓冲区大小
taos_options(TSDB_OPTION_CONFIGDIR, "/etc/taos");
// 调整缓冲区配置以优化BLOB写入性能
7.3 存储优化
-- 创建表时考虑数据分片
CREATE TABLE vehicle_data (
ts TIMESTAMP,
vehicle_id NCHAR(20),
raw_data BLOB,
device_status BLOB
) TAGS (region NCHAR(10), vehicle_type NCHAR(20));
-- 按标签分布数据以提高查询性能
CREATE TABLE vehicle_beijing USING vehicle_data TAGS ('beijing', 'truck');
CREATE TABLE vehicle_shanghai USING vehicle_data TAGS ('shanghai', 'car');
8. 使用限制
8.1 数据类型限制
- 最大长度限制:BLOB 字段数据的总长度上限为4MB (4,194,304字节)
- 字段数量:BLOB 字段数目不做限制,可以在一个表中定义多个BLOB列
- 标签限制:BLOB 不能定义为标签列
- 主键限制:BLOB 不能定义为复合主键列
-- ❌ 错误:BLOB 不能作为标签
CREATE STABLE vehicle_data (
ts TIMESTAMP,
vehicle_id NCHAR(20),
raw_data BLOB
) TAGS (config_data BLOB); -- 错误!
-- ❌ 错误:BLOB 不能作为主键
CREATE TABLE device_config (
config_data BLOB PRIMARY KEY, -- 错误!
ts TIMESTAMP,
device_id NCHAR(20)
);
-- ✅ 正确:正常的 BLOB 列定义
CREATE TABLE vehicle_data (
ts TIMESTAMP,
vehicle_id NCHAR(20),
raw_data BLOB,
device_status BLOB,
config_backup BLOB -- 可以定义多个BLOB列
);
8.2 操作限制
8.2.1 不支持的操作
-- ❌ 不支持比较操作
SELECT * FROM vehicle_data WHERE raw_data > '\x123456'; -- 错误
-- ❌ 不支持排序
SELECT * FROM vehicle_data ORDER BY raw_data; -- 错误
-- ❌ 不支持分组
SELECT COUNT(*) FROM vehicle_data GROUP BY raw_data; -- 错误
-- ❌ 不支持连接条件
SELECT * FROM vehicle_data v1, vehicle_data v2
WHERE v1.raw_data = v2.raw_data; -- 错误
8.2.2 支持的操作
-- ✅ 支持NULL判断
SELECT * FROM vehicle_data WHERE raw_data IS NULL;
SELECT * FROM vehicle_data WHERE raw_data IS NOT NULL;
-- ✅ 支持投影查询
SELECT ts, vehicle_id, raw_data FROM vehicle_data;
-- ✅ 支持 UNION ALL
SELECT raw_data FROM vehicle_data
UNION ALL
SELECT radar_data FROM flight_data;
8.3 函数限制
BLOB 类型支持的函数与 VARCHAR 相同,但有以下限制:
-- ✅ 支持的函数
SELECT LENGTH(raw_data) FROM vehicle_data; -- 获取字节长度
SELECT SUBSTRING(raw_data, 1, 100) FROM vehicle_data; -- 子串提取
-- ❌ 不支持的函数(字符串相关)
SELECT UPPER(raw_data) FROM vehicle_data; -- 错误
SELECT LOWER(raw_data) FROM vehicle_data; -- 错误
SELECT CONCAT(raw_data, device_status) FROM vehicle_data; -- 错误
9. 应用场景
9.1 车联网场景
-- 车联网数据表设计
CREATE STABLE vehicle_telemetry (
ts TIMESTAMP,
vehicle_id NCHAR(20),
can_bus_data BLOB, -- CAN 总线原始数据
gps_data BLOB, -- GPS 数据包
sensor_data BLOB, -- 传感器数据
camera_data BLOB -- 摄像头数据
) TAGS (
region NCHAR(20),
vehicle_model NCHAR(30),
manufacturer NCHAR(30)
);
-- 创建子表
CREATE TABLE vehicle_bj_001 USING vehicle_telemetry
TAGS ('Beijing', 'Model_X', 'Tesla');
-- 插入数据
INSERT INTO vehicle_bj_001 VALUES (
NOW,
'BJ001',
'\x7E010203040506070E', -- CAN 数据
'\x474153504441544A', -- GPS 数据
'\x53454E534F52444154', -- 传感器数据
'\x43414D4552414441' -- 摄像头数据
);
9.2 航空场景
-- 航空数据表设计
CREATE STABLE flight_telemetry (
ts TIMESTAMP,
flight_id NCHAR(10),
flight_plan NCHAR(50),
radar_raw_data BLOB, -- 雷达原始数据
ads_b_data BLOB, -- ADS-B 数据
weather_data BLOB, -- 气象数据
communication_log BLOB -- 通信日志
) TAGS (
airport NCHAR(10),
aircraft_type NCHAR(20),
airline NCHAR(30)
);
-- 查询特定时间段的航班数据
SELECT ts, flight_id, LENGTH(radar_raw_data) as radar_size,
LENGTH(ads_b_data) as ads_b_size
FROM flight_telemetry
WHERE ts >= '2024-01-01 00:00:00'
AND ts < '2024-01-02 00:00:00'
AND radar_raw_data IS NOT NULL;
9.3 工业物联网场景
-- 工业设备监控表
CREATE STABLE industrial_monitor (
ts TIMESTAMP,
device_id NCHAR(32),
production_line NCHAR(20),
raw_sensor_data BLOB, -- 原始传感器数据
plc_data BLOB, -- PLC 数据
scada_data BLOB, -- SCADA 系统数据
maintenance_log BLOB -- 维护日志
) TAGS (
factory NCHAR(30),
equipment_type NCHAR(20),
manufacturer NCHAR(30)
);
-- 分析设备运行状态
SELECT device_id, COUNT(*) as data_points,
AVG(LENGTH(raw_sensor_data)) as avg_data_size,
MAX(LENGTH(raw_sensor_data)) as max_data_size
FROM industrial_monitor
WHERE ts >= NOW - INTERVAL(24, HOUR)
AND raw_sensor_data IS NOT NULL
GROUP BY device_id;
10. 故障排除
10.1 常见错误
10.1.1 数据长度超限
错误信息:BLOB data too long
原因:BLOB 数据超过 4MB 限制
解决方案:
1. 检查数据大小,确保不超过 4MB
2. 考虑数据压缩或分割存储
10.1.2 类型不匹配
错误信息:Invalid data type for BLOB column
原因:尝试插入不兼容的数据类型
解决方案:
1. 确保使用正确的十六进制格式(\x前缀)
2. 检查参数绑定时的数据类型设置
10.1.3 NULL 值处理
-- ❌ 错误的NULL插入
INSERT INTO vehicle_data VALUES (NOW, 'VH001', NULL, '');
-- ✅ 正确的NULL插入
INSERT INTO vehicle_data VALUES (NOW, 'VH001', NULL, NULL);
10.2 性能问题排查
10.2.1 写入性能差
可能原因:
- 单条插入而非批量插入
- 未使用参数绑定写入
- 缓冲区配置不当
解决方案:
// 使用批量插入
TAOS_STMT *stmt = taos_stmt_init(taos);
for (int i = 0; i < BATCH_SIZE; i++) {
taos_stmt_bind_param(stmt, params);
taos_stmt_add_batch(stmt);
if (i % 100 == 0) { // 每100条提交一次
taos_stmt_execute(stmt);
}
}
10.2.2 查询性能差
可能原因:
- 缺少合适的时间过滤条件
- 查询了不必要的 BLOB 列
解决方案:
-- ❌ 低效查询
SELECT * FROM vehicle_data;
-- ✅ 高效查询
SELECT ts, vehicle_id, LENGTH(raw_data) as data_size
FROM vehicle_data
WHERE ts >= NOW - INTERVAL(1, HOUR)
AND raw_data IS NOT NULL;
10.3 调试技巧
10.3.1 数据验证
// 验证BLOB数据完整性
int validate_blob_data(const char* data, int length) {
if (data == NULL || length <= 0) {
printf("BLOB数据为空\n");
return -1;
}
if (length > TSDB_MAX_BLOB_LEN) {
printf("BLOB数据超长: %d > %d\n", length, TSDB_MAX_BLOB_LEN);
return -1;
}
printf("BLOB数据验证通过,长度: %d字节\n", length);
return 0;
}
10.3.2 十六进制数据检查
// 检查十六进制格式
int check_hex_format(const char* hex_str) {
if (hex_str == NULL || strlen(hex_str) < 2) {
return -1;
}
if (hex_str[0] != '\\' || hex_str[1] != 'x') {
printf("缺少\\x前缀\n");
return -1;
}
for (int i = 2; hex_str[i] != '\0'; i++) {
if (!isxdigit(hex_str[i])) {
printf("非法十六进制字符: %c\n", hex_str[i]);
return -1;
}
}
return 0;
}
11. 总结
TDengine 的 BLOB 数据类型为处理大容量二进制数据提供了强大的支持,特别适用于车联网、航空、工业物联网等场景。通过独立的 BSE 存储引擎,BLOB 类型在保证数据完整性的同时显著提升了写入性能。
主要优势:
- 大容量:支持最大4MB的数据存储
- 高性能:写入性能相比Binary类型提升显著
- 灵活性:支持多种写入和查询方式
- 稳定性:独立存储引擎确保数据安全
使用建议:
- 优先使用批量插入和参数绑定写入
- 合理设计表结构和标签分布
- 注意数据类型限制和操作约束
- 定期监控性能和存储使用情况
通过合理使用 BLOB 数据类型,可以有效解决大容量二进制数据的存储和处理需求,为时序数据库应用场景提供更强大的支持。
关于 TDengine
TDengine 是一款专为物联网、工业互联网等场景设计并优化的大数据平台,其核心模块是高性能、集群开源、云原生、极简的时序数据库。
它能安全高效地将大量设备每天产生的高达 TB 甚至 PB 级的数据进行汇聚、存储、分析和分发,并提供 AI 智能体对数据进行预测与异常检测,提供实时的商业洞察。