(给DotNet加星标,提升.Net技能)
转自:邵佳楠 cnblogs.com/ShaoJianan/p/11163091.html
不喜欢拿一堆数据的运行耗时来对比各个解决方案的性能等,有时候看一些测评长篇大论写耗时的一些对比,有时就差个 几百毫秒 我觉得也没啥必要,关键是好用就行一切从简我写博客也喜欢一切从简。
.NET操作Clickhouse的库比较少,大多数都是基于ClickHouse.ADO的一个封装,下面也主要介绍一下ClickHouse.ADO的使用,以及自己封装的一个库的使用。
前言
Clickhouse适用于大数据量分析,我的应用场景是每十秒从公交轨迹中取固定时间段数据分析一些情况,电脑配置就是普通的开发配置,总体数据轨迹量在3亿左右,处理的数据时间段在一天以内,取出的数据量在2.3万条左右。大家可以当个借鉴!
一、具体操作
简单的查询和新增以及批量新增(Clickhouse不推荐数据的编辑和删除此处就不再举例)
public class Demo
{
private ClickHouseConnection GetConnection(string cstr= "Compress=True;CheckCompressedHash=False;Compressor=lz4;Host=ch-test.flippingbook.com;Port=9000;Database=default;User=andreya;Password=123")
{
var settings = new ClickHouseConnectionSettings(cstr);
var cnn = new ClickHouseConnection(settings);
cnn.Open();
return cnn;
}
/*查询*/
public void Select()
{
using (var cnn = GetConnection())
{
var reader = cnn.CreateCommand("SELECT * FROM test").ExecuteReader()
......省略
}
}
/*增加*/
public void Insert()
{
using (var cnn = GetConnection())
{
var cmd = cnn.CreateCommand("INSERT INTO test (date,x, arr)values ('2017-01-01',1,['a','b','c'])");
cmd.ExecuteNonQuery();
}
}
/*批量新增*/
public void InsertBulk()
{
using (var cnn = GetConnection())
{
var cmd = cnn.CreateCommand("INSERT INTO test (date,x, values.name,values.value)values @bulk;");
cmd.Parameters.Add(new ClickHouseParameter
{
DbType = DbType.Object,
ParameterName = "bulk",
Value = new[]
{
new object[] {DateTime.Now, 1, new[] {"aaaa@bbb.com", "awdasdas"}, new[] {"dsdsds", "dsfdsds"}},
new object[] {DateTime.Now.AddHours(-1), 2, new string[0], new string[0]},
}
});
cmd.ExecuteNonQuery();
}
}
}
二、帮助类
鉴于使用原始方法读取数据后转换的方式太麻烦,分页等也需要自己实现,所以写了一个帮助类,方便操作。
Clickhouse:https://github.com/i542873057/ClickHouseHelper
使用方式也很简单,如下:
public HistoryModel GetHistories(string busid, string begindt, string enddt)
{
using (var helper = new ClickHouseHelper())
{
try
{
HistoryModel historyModel = new HistoryModel();
historyModel.Histories = helper .ExecuteList<HistoriesModel>($"select mile,speed,lon,lat,direct,termtime from its.gps_MergeTree where termtime >='{begindt}' and termtime<='{enddt}' and busid={busid} order by termtime");
historyModel.Inouts = helper .ExecuteList<InoutModel>($"SELECT * FROM its.inout_t WHERE Adtime>='{begindt}' and Adtime<='{enddt}' and Busid={busid} order by Recvtime");
//clickhouse中取出来的时间默认会有时区的问题,这里需要手动转下本地的时区
historyModel.Histories.ForEach(u => u.termtime = DateTime.Parse(u.termtime).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"));
historyModel.Inouts.ForEach(u => u.Recvtime = u.Recvtime.ToLocalTime());
return historyModel;
}
catch (Exception e)
{
ckhelper.Dispose();
Console.WriteLine(e);
throw;
}
}
}
三、一些小问题记录
1、时区问题
Clickhosue中取出来的时候会多8个小时,之前一度怀疑安装时服务器时区不对,但实际上都是正确的,只能手动将时间通过ToLocalTime转成本地时区
2、批量插数据
批量插数据的时候如果传入一个List的话,对应的类需要增加GetEnumerator方法,就像这样
public class Demo
{
public string obu { get; set; }
public int busid { get; set; }
public string buscode { get; set; }
public IEnumerator GetEnumerator()
{
yield return obu;
yield return busid;
yield return buscode;
.....
}
}
3、类型统一问题
错误详情:
Unable to cast object of type
System.Double' to type 'System.Single'
错误原因是由于程序中的类型与clickhouse中的数据类型不匹配导致
如上问题是由于clickhouse中数据类型为float32,程序中的类型为double就会引起上述问题,附上部分数据类型对应关系:
推荐阅读
(点击标题可跳转阅读)
看完本文有收获?请转发分享给更多人
关注「DotNet」加星标,提升.Net技能
好文章,我在看❤️