美文网首页.NET超级程序猿dotNET
.Net轻松处理亿级数据--ClickHouse数据操作

.Net轻松处理亿级数据--ClickHouse数据操作

作者: 邵佳楠 | 来源:发表于2019-07-05 10:56 被阅读2次

    该篇内容由个人博客点击跳转同步更新!转载请注明出处!

    .Net操作Clickhouse的库比较少,大多数都是基于ClickHouse.ADO的一个封装,下面也主要介绍一下ClickHouse.ADO的使用,以及自己封装的一个库的使用。

    前言

    Clickhouse适用于大数据量分析,我的应用场景是每十秒从公交轨迹中取固定时间段数据分析一些情况,时间段在一天以内,数据量在2亿左右,取出的数据量在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,点击跳转

    帮助类

    使用方式也很简单,如下:

    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;
                .....
            }
    }
    
    1. 类型统一问题
      具体参考我的这篇文章 点击跳转

    微信关注我哦!(转载注明出处) 关注我哦

    相关文章

      网友评论

        本文标题:.Net轻松处理亿级数据--ClickHouse数据操作

        本文链接:https://www.haomeiwen.com/subject/qglchctx.html