IoTDB数据库的使用
网址:
https://iotdb.apache.org/zh/
源码,里面有C#的示例代码:
https://github.com/apache/iotdb-client-csharp
快速上手
https://iotdb.apache.org/zh/UserGuide/V1.2.x/QuickStart/QuickStart.html
服务端
服务端的下载页面:
https://iotdb.apache.org/Download/
我下载了最新的1.2.2版本。
下载完整后执行批处理文件:
sbin\start-standalone.bat
运行时报错:
"setting local JMX..."
Maximum memory allocation pool = 8140M, initial memory allocation pool = 600M
If you want to change this configuration, please check conf\datanode-env.bat.
Check whether the ports are occupied....
JAVA_HOME environment variable must be set
看了一下提示,应该是缺少JDK,于是便下载安装了最新的JDK,并且配置了JAVA_HOME。
再次执行start-standalone.bat批处理,运行正常。
客户端调用
安装Nuget包:
Install-Package Apache.IoTDB
示例代码:
// 参数定义
using Apache.IoTDB.DataStructure;
using Apache.IoTDB;
string host = "localhost";
int port = 6667;
int pool_size = 2;
// 初始化session
var session_pool = new SessionPool(host, port, pool_size);
// 开启session
await session_pool.Open(false);
// 创建时间序列
await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED);
await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED);
await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED);
// 插入record
var measures = new List<string> { "ts1", "ts2", "ts3" };
var values = new List<object> { "test_text", true, (int)123 };
var timestamp = 1;
var rowRecord = new RowRecord(timestamp, values, measures);
await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord);
// 插入Tablet
var timestamp_lst = new List<long> { timestamp + 1 };
var value_lst = new List<List<object>> { new List<object> { "iotdb", true, (int)12 } };
var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst);
await session_pool.InsertTabletAsync(tablet);
// 关闭Session
await session_pool.Close();
CreateTimeSeries介绍
-
session_pool
: 这是一个SessionPool
对象,它是与Apache IoTDB服务器交互的主要接口。session_pool
通常在应用程序启动时创建,并用于获取和管理与IoTDB的会话。 -
CreateTimeSeries
: 这是SessionPool
类的一个方法,用于在IoTDB中创建一个新的时间序列。 -
"root.test_group.test_device.ts1"
: 这是一个字符串参数,表示要创建的时间序列的全路径。在Apache IoTDB中,时间序列的路径采用层次结构的形式,由多级节点组成。在这个例子中,路径表示根节点下的"test_group"分组下的"test_device"设备下的"ts1"时间序列。 -
TSDataType.TEXT
: 这是一个枚举参数,定义了时间序列的数据类型。TSDataType
枚举包含了多种数据类型,如INT32、INT64、FLOAT、DOUBLE、BOOLEAN、TEXT等。在这个例子中,时间序列的数据类型被设置为TEXT,表示存储文本数据。 -
TSEncoding.PLAIN
: 这是一个枚举参数,定义了时间序列的数据编码方式。TSEncoding
枚举包含了多种编码方式,如PLAIN、PLAIN_DICTIONARY、RLE、DIFF、TS_2DIFF等。在这个例子中,时间序列的数据编码方式被设置为PLAIN,表示使用原始数据格式存储。 -
Compressor.UNCOMPRESSED
: 这是一个枚举参数,定义了时间序列的数据压缩方式。Compressor
枚举包含了多种压缩算法,如UNCOMPRESSED、SNAPPY、GZIP、LZ4等。在这个例子中,时间序列的数据压缩方式被设置为UNCOMPRESSED,表示不进行数据压缩。
TSEncoding.PLAIN介绍
TSEncoding.PLAIN是Apache IoTDB中的一种数据编码方式,它表示使用原始数据格式存储时间序列的数据。PLAIN编码是最简单、最直接的编码方式,不进行任何特殊的数据转换或压缩。
相比之下,Apache IoTDB还提供了其他几种数据编码方式,每种方式都有其特定的应用场景和优缺点:
-
PLAIN_DICTIONARY:
PLAIN_DICTIONARY编码是一种字典编码方式,适用于值域较小且重复次数较多的数据。在这种编码下,IoTDB会维护一个字典,将原始数据映射为字典中的索引。这样可以减少存储空间,特别是当数据中有大量重复值时。然而,查询时需要额外的解码步骤,可能会增加一些计算开销。 -
RLE:
RLE(Run-Length Encoding)编码是一种简单的无损压缩方法,用于存储连续重复的值。如果数据中有很长的连续相同值的序列,RLE编码可以显著减少存储空间。但是,对于没有或很少重复值的数据,RLE编码可能不会带来太大的压缩效果。 -
DIFF:
DIFF编码基于前后值的差分进行存储,适用于连续数据值变化相对平滑的情况。这种编码可以减少存储空间,特别是当数据值的变化相对较小的时候。然而,查询时需要进行差分逆运算来恢复原始数据,可能会增加计算复杂性。 -
TS_2DIFF:
TS_2DIFF编码是对DIFF编码的进一步优化,它存储的是连续两个数据点的差分。这种编码在数据变化更加平滑的情况下能提供更好的压缩效果,但同样在查询时需要进行更复杂的逆运算来恢复原始数据。
查询数据
//string query = "SELECT * FROM root.test_group.test_device where time>1";
//string query = "SELECT * FROM root.test_group.test_device";
string query = "SELECT ts1,ts2 FROM root.test_group.test_device";
SessionDataSet resultSet = await session_pool.ExecuteQueryStatementAsync(query);
// 打印列名
Console.WriteLine(string.Join(", ", resultSet.ColumnNames));
while (resultSet.HasNext())
{
RowRecord record = resultSet.Next();
//Console.WriteLine(record.Values.StringJoin(", "));
Console.WriteLine(record.ToString());
}
SELECT * FROM root.test_group.test_device
相当于查询test_group.test_device下的所有参数
SELECT * FROM root.test_group.test_device where time>1
限制一下时间,只返回time大于1的。
SELECT ts1,ts2 FROM root.test_group.test_device
只返回需要的两个序列。感觉这里的序列有点像关系型数据库的表字段。
性能测试
下面是测试代码:
#if true
await session_pool.CreateTimeSeries("root.test_group.real_data.A", TSDataType.DOUBLE, TSEncoding.PLAIN, Compressor.UNCOMPRESSED);
await session_pool.CreateTimeSeries("root.test_group.real_data.B", TSDataType.DOUBLE, TSEncoding.PLAIN, Compressor.UNCOMPRESSED);
await session_pool.CreateTimeSeries("root.test_group.real_data.C", TSDataType.DOUBLE, TSEncoding.PLAIN, Compressor.UNCOMPRESSED);
await session_pool.CreateTimeSeries("root.test_group.real_data.D", TSDataType.DOUBLE, TSEncoding.PLAIN, Compressor.UNCOMPRESSED);
var measures = new List<string> { "A", "B", "C", "D" };
var timestamp_lst = new List<long>();
var value_lst = new List<List<object>>();
Random random = new Random();
for (int i = 0; i < 1000 * 10000; i++)
{
timestamp_lst.Add(i + 1000 * 10000);
var dataList = new List<object>();
dataList.Add(random.NextDouble());
dataList.Add(random.NextDouble());
dataList.Add(random.NextDouble());
dataList.Add(random.NextDouble());
value_lst.Add(dataList);
}
Stopwatch stopwatch = Stopwatch.StartNew();
var tablet = new Tablet("root.test_group.real_data", measures, value_lst, timestamp_lst);
await session_pool.InsertTabletAsync(tablet);
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.ToString());
#endif
string query = "SELECT * FROM root.test_group.real_data";
SessionDataSet resultSet = await session_pool.ExecuteQueryStatementAsync(query);
stopwatch.Restart();
var myList = new List<TestInfo>();
while (resultSet.HasNext())
{
RowRecord record = resultSet.Next();
TestInfo info = new TestInfo();
info.A = (double)record.Values[0];
info.B = (double)record.Values[1];
info.C = (double)record.Values[2];
info.D = (double)record.Values[3];
myList.Add(info);
}
stopwatch.Stop();
Console.WriteLine(myList.Count);
Console.WriteLine(stopwatch.Elapsed.ToString());
public class TestInfo
{
public double A { get; set; }
public double B { get; set; }
public double C { get; set; }
public double D { get; set; }
}
每条记录是4个字段。
每次插入1000万条数据,第2次插入时返回的结果:
00:00:13.1639352
20000000
00:00:21.8426342
相当于插入1千万条记录耗时是13秒,返回2千万条数据耗时是21秒。
另外,值得注意的是,timestamp有点类似数据的关键字,如果timestamp设置成一样的话,老的数据是会被新数据覆盖的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧