ClickHouse基础知识及与MySQL性能对比

文章目录

        • ClickHouse介绍
        • 如何理解OLTP和OLAP
        • 如何理解行式存储和列式存储
        • ClickHouse应用场景
        • ClickHouse引擎
          • Log系列引擎
          • MergeTree系列表引擎
            • CollapsingMergeTree
            • VersionedCollapsingMergeTree
            • SummingMergeTree
            • AggregatingMergeTree
          • 外部存储引擎
            • HDFS引擎
            • mysql引擎
            • File引擎
          • 内部引擎
            • Memory
            • Set
            • Buffer
        • ClickHouse SQL操作
          • create
            • CREATE DATABASE
            • CREATE TABLE
          • insert into
          • update和delete
          • select操作
          • alter操作
          • describe table
        • ClickHouse数据压缩
          • 通用编码
          • 特殊编码
          • 使用
          • 压缩效果对比
        • ClickHouse索引
          • 稀疏索引
          • 索引粒度
          • 索引文件
          • 标记文件
          • 索引工作方式
        • ClickHouse性能
          • 单个查询吞吐量
          • 处理短查询的延时时间
          • 处理大量短查询
          • 数据写入性能
          • mysql与ClickHouse性能写入区别?
        • springboot、mybatis-plus及ClickHouse整合
          • 依赖
          • 配置
          • 使用注意点
        • mysql数据迁移ClickHouse
          • ClickHouse同步建表
          • 建表语句
        • ClickHouse待解决问题

ClickHouse介绍

Clickhouse是俄罗斯yandex公司于2016年开源的一个列式数据库管理系统,在OLAP领域像一匹黑马一样,以其超高的性能受到业界的青睐。特性:

  • 基于shard+replica实现的线性扩展和高可靠
  • 采用列式存储,数据类型一致,压缩性能更高
  • 硬件利用率高,连续IO,提高了磁盘驱动器的效率
  • 向量化引擎与SIMD提高了CPU利用率,多核多节点并行化大查询

不足:

  • 不支持事务、异步删除与更新
  • 不适用高并发场景
如何理解OLTP和OLAP

OLTP是Online transaction processing的英文缩写,指在线/联机事务处理,这么说其实还是比抽象的。OLTP典型的应用领域包括银行、证劵等金融行业,电子商务系统等,在此举最经典的银行例子,我们在招商银行APP上查询账户余额、收支信息和转账记录,在ATM机上存钱,取钱,将招行账号的钱转到工行账号上。这些都是典型的OLTP类操作,这些操作都比较简单,主要是对数据库中的数据进行增删改查。操作主体一般是产品的用户。

OLAP是Online analytical processing的英文缩写,指联机分析处理。从字面上我们能看出是做分析类操作。通过分析数据库中的数据来得出一些结论性的东西。比如给老总们看的报表,用于进行市场开拓的用户行为统计,不同维度的汇总分析结果等等。操作主体一般是运营、销售和市场等团队人员而不是用户。

单次OLTP处理的数据量比较小,所涉及的表非常有限,一般仅一两张表。而OLAP是为了从大量的数据中找出某种规律性的东西,经常用到count()、sum()和avg()等聚合方法,用于了解现状并为将来的计划/决策提供数据支撑,所以对多张表的数据进行连接汇总非常普遍。

为了表示跟OLTP的数据库(database)在数据量和复杂度上的不同,一般称OLAP的操作对象为数据仓库(data warehouse),简称数仓。数据库仓库中的数据,往往来源于多个数据库,以及相应的业务日志。

下表是对OLTP和OLAP的简单总结。
ClickHouse基础知识及与MySQL性能对比_第1张图片

如何理解行式存储和列式存储

列式存储是指一列中的数据在存储介质中是连续存储的;行式存储是指一行中的数据在存储介质中是连续存储的。简单的说,你可以把列式数据库认为是每一列都是一个表,这个表只有一列,如果只在该列进行条件查询,速度就很快。

行数据库适用于读取出少行,多列的情况;列数据库相反,适用于读取出少数列,多数行的情况。

列数据库可以节省空间,如果某一行的某一列没有数据,那在列存储时,就可以不存储该列的值。

传统的行式数据库将一个个完整的数据行存储在数据页中。这种方式在大数据量查询的时候会出现以下问题:在没有索引的情况下,会把一行全部查出来,查询会使用大量IO;虽然建立索引和物化视图可以可以快速定位列,但是也需要花费大量时间。但是如果处理查询时需要用到大部分的数据列,这种方式在磁盘IO上是比较高效的。
一般来说,OLTP(Online Transaction Processing,联机事务处理)应用适合采用这种方式。

列式数据库是将同一个数据列的各个值存放在一起。插入某个数据行时,该行的各个数据列的值也会存放到不同的地方。因此,列式数据库大大地提高了OLAP大数据量查询的效率。当然,列式数据库不是万能的,每次读取某个数据行时,需要分别从不同的地方读取各个数据列的值,然后合并在一起形成数据行。因此,如果每次查询涉及的数据量较小或者大部分查询都需要整行的数据,列式数据库并不适用。

ClickHouse应用场景

1.绝大多数请求都是用于读访问的
2.数据需要以大批次(大于1000行)进行更新,而不是单行更新;或者根本没有更新操作
3.数据只是添加到数据库,没有必要修改
4.读取数据时,会从数据库中提取出大量的行,但只用到一小部分列
5.表很“宽”,即表中包含大量的列
6.查询频率相对较低(通常每台服务器每秒查询数百次或更少)
7.对于简单查询,允许大约50毫秒的延迟
8.列的值是比较小的数值和短字符串(例如,每个URL只有60个字节)
9.在处理单个查询时需要高吞吐量(每台服务器每秒高达数十亿行)
10.不需要事务
11.数据一致性要求较低
12.每次查询中只会查询一个大表。除了一个大表,其余都是小表
13.查询结果显著小于数据源。即数据有过滤或聚合。返回结果不超过单个服务器内存大小

ClickHouse引擎
Log系列引擎

Log家族具有最小功能的轻量级引擎。当您需要快速写入许多小表(最多约100w行)并在以后整体读取它们时,该类型的引擎是最有效的。

1、TinyLog引擎

  • 将数据存储在磁盘上,没有索引,没有标记块
  • 每列都存储在单独的压缩文件中
  • 数据写入时追加写到文件末尾
  • 该引擎没有并发控制,不允许同时读写

2、StripeLog引擎(数据分块列在一起)

3、Log引擎(数据分块记录偏移量)

  • *.bin存储每个字段的数据
  • mark.mrk数据块标记
  • 支持多线程处理
  • 并发读写
MergeTree系列表引擎

MergeTree系列的表引擎支持主键索引、数据分区、数据副本和数据采样这些特性,同时也只有此系列的表引擎支持ALTER相关操作

特点:

  • 存储按主键排序的数据
  • 如果指定了分区键,则可以使用分区
  • 数据复制支持:ReplacedMergeTree表族提供数据复制。
  • 数据采样支持
create table tb_merge_tree(
id Int8 ,
name String ,
ctime Date
)engine=MergeTree()
partition by name  --选填,如果不声明分区键,则ClickHouse会生成一个名为all的分区。
order by id --必填,默认情况下主键(PRIMARY KEY)与排序键相
primary id --选填,主键字段生成一级索引,主键允许存在重复数据
sample by intHash32(id) --选填,用于声明数据以何种标准进行采样
settings index_granularity = 8192,  --选填,索引的粒度
index_granularity_bytes  = 0, --自适应间隔大小,根据每一批次写入数据的体量大小,动态划分间隔大小。0表示不启动自适应功能。
enable_mixed_granularity_parts = true, --选填,是否开启自适应索引间隔的功能,默认开启
merge_with_ttl_timeout = 10, --选填,数据TTL功能
storage_policy = 1; --选填,多路径存储策略

MergeTree表引擎中的数据是拥有物理存储的,数据会按照分区目录的形式保存到磁盘上。

ClickHouse基础知识及与MySQL性能对比_第2张图片

一张数据表的完整物理结构分为3个层级,依次是数据表目录、分区目录各分区下具体的数据文件

  • checksums.txt:校验文件,使用二进制格式存储。用于快速校验文件的完整性和正确性。
  • columns.txt:列信息文件,使用明文格式存储。用于保存次数据分区下的列字段信息。
  • count.txt:计数文件,使用明文格式存储。用于记录当前数据分区目录下的总行数。
  • primary.idx:一级索引文件,使用二进制格式存储,用于存放稀疏索引,一张MergeTree表只能声明一次稀疏索引(通过order by 或 primary key)
  • [column].bin:数据文件,使用压缩格式存储,默认为LZ4压缩格式,用于存储某一列的数据,每一个列字段都拥有独立的.bin数据文件,并以列字段名称命名(如CounterID.bin)
  • [column].mrk:列字段标记文件,使用二进制格式存储,标记文件中保存了.bin文件中数据的偏移量信息。标记文件与稀疏索引对齐,又与.bin文件一一对应,所以MergeTree通过标记文件建立了primary.idx稀疏索引与.bin数据文件之间的映射关系
  • [column].mrk2:如果使用了自适应大小的索引间隔,则标记文件会以.mrk2命名。它的工作原理和作用与.mrk标记文件相同。
  • partition.dat与minmax_[Column].idx:如果使用了分区键,则会额外生成partition.dat与minmax索引文件,它们均使用二进制格式存储。partition.dat用于保存当前分区下分区表达式最终生成的值;而minmax索引用于记录当前分区下分区字段对应原始数据的最小和最大值。
CollapsingMergeTree

CollapsingMergeTree是一种通过以增代删的思路,支持行级数据修改和删除的表引擎。

通过定义一个sign标记位字段,记录数据行的状态。如果sign标记为1,则表示这是一行有效的数据;如果sign标记为-1,则表示这行数据需要被删除。当CollapsingMergeTree分区合并时,同一数据分区内,sign标记为1和-1的一组数据会被抵消删除。

**注意:**CollapsingMergeTree虽然解决了主键相同的数据即时删除的问题,但是状态持续变化且多线程并行写入情况下,状态行与取消行位置可能乱序,导致无法正常折叠。只有保证老的状态行在在取消行的上面, 新的状态行在取消行的下面! 但是多线程无法保证写的顺序!

VersionedCollapsingMergeTree

解决CollapsingMergeTree乱序写入情况下无法正常删除(折叠)问题,在建表语句中新增了一列version,用于在乱序情况下记录状态行与取消行的对应关系

主键(排序)相同,且version相同,sign相反的行,在合并时会被删除。

SummingMergeTree

只需要查询汇总结果,不关心明细数据。并且数据的汇总条件是预先明确的(group by条件明确,不会随意改变)

AggregatingMergeTree

通过定义AggregateFunction(聚合函数,数据类型) 决定针对哪些列字段计算。

写入时需要使用-state语法,查询时使用-merge语法。

外部存储引擎
HDFS引擎

clickhouse可以直接从HDFS中指定的目录下加载数据,自己不存储数据,仅仅读取数据

engine=HDFS('hdfs://linux01:8020/ck/test/*','csv')
-clickhouse支持的文件格式有CSV、TSV、JSON等
mysql引擎
engine=MYSQL('localhost:3306','test','test','root','123456')
File引擎
内部引擎
Memory
Set
Buffer
ClickHouse SQL操作

基本上来说传统关系型数据库(以MySQL为例)的SQL语句,基本支持但是也有不一样的地方

create
CREATE DATABASE

用于创建指定名称的数据库,语法如下:CREATE DATABASE [IF NOT EXISTS] db_name

CREATE TABLE
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = engine
 
// DEFAULT expr – 默认值,用法与SQL类似。
// MATERIALIZED expr – 物化表达式,被该表达式指定的列不能被INSERT,因为它总是被计算出来的,对于INSERT而言,不需要考虑这些列。 另外,在SELECT查询中如果包含星号,此列不会被查询。
// ALIAS expr – 别名。
 
 
// 有三种方式创建表:
1)直接创建
:) create table t1(id UInt16,name String) engine=TinyLog
 
2)创建一个与其他表具有相同结构的表
CREATE TABLE [IF NOT EXISTS] [db.]table_name AS [db2.]name2 [ENGINE = engine]
可以对其指定不同的表引擎声明。如果没有表引擎声明,则创建的表将与db2.name2使用相同的表引擎。
 
3)使用指定的引擎创建一个与SELECT子句的结果具有相同结构的表,并使用SELECT子句的结果填充它。
CREATE TABLE [IF NOT EXISTS] [db.]table_name ENGINE = engine AS SELECT ...
insert into
// 主要用于向表中添加数据,基本格式如下:INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ...
// 实例:insert into t1 values(1,'zhangsan'),(2,'lisi'),(3,'wangwu')
 
// 还可以使用select来写入数据,基本格式如下:INSERT INTO [db.]table [(c1, c2, c3)] SELECT ...
// 实例:insert into t2 select * from t3
update和delete

ClickHouse提供了Delete 和Update的能力,这类操作被称为Mutation查询,它可以看做Alter 的一种。

虽然可以实现修改和删除,但是和一般的OLTP数据库不一样,Mutation语句是一种很“重”的操作,而且不支持事务。

“重”的原因主要是每次修改或者删除都会导致放弃目标数据的原有分区,重建新分区。所以尽量做批量的变更,不要进行频繁小数据的操作。

// 删除操作
alter table t_order_smt delete where sku_id ='sku_001';
 
// 修改操作
alter table t_order_smt update total_amount=toDecimal32(2000.00,2) where id =102;
 
// 由于操作比较“重”,所以 Mutation语句分两步执行,同步执行的部分其实只是进行新增数据新增分区和并把旧分区打上逻辑上的失效标记。知道触发分区合并的时候,才会删除旧数据释放磁盘空间。
select操作

clickhouse基本上与标准SQL 差别不大。

支持子查询

支持CTE(with 子句)

支持各种JOIN, 但是JOIN操作无法使用缓存,所以即使是两次相同的JOIN语句,Clickhouse也会视为两条新SQL。

不支持窗口函数。

不支持自定义函数。

GROUP BY 操作增加了 with rollup\with cube\with total 用来计算小计和总计。

create table t_order_mt(
    id UInt32,
    sku_id String,
    total_amount Decimal(16,2),
    create_time  Datetime
 ) engine = MergeTree
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
 
insert into  t_order_mt values(101,'sku_001',1000.00,'2020-08-01 12:00:00’);
insert into  t_order_mt values(102,'sku_002',2000.00,'2020-08-01 12:00:00');
insert into  t_order_mt values(103,'sku_004',2500.00,'2020-08-01 12:00:00');
insert into  t_order_mt values(104,'sku_002',2000.00,'2020-08-01 12:00:00');
insert into  t_order_mt values(105,'sku_003',600.00,'2020-08-02 12:00:00);
insert into  t_order_mt values(105,'sku_004',600.00,'2020-08-02 12:00:00');
insert into  t_order_mt values(106,'sku_001',1000.00,'2020-08-04 12:00:00');
insert into  t_order_mt values(107,'sku_002',2000.00,'2020-08-04 12:00:00');
insert into  t_order_mt values(108,'sku_004',2500.00,'2020-08-04 12:00:00');
insert into  t_order_mt values(109,'sku_002',2000.00,'2020-08-04 12:00:00');
insert into  t_order_mt values(110,'sku_003',600.00,'2020-08-01 12:00:00');
 
// with rollup : 从右至左去掉维度进行小计。
 
select id , sku_id,sum(total_amount) from  t_order_mt group by id,sku_id with rollup;
 
// with cube : 从右至左去掉维度进行小计,再从左至右去掉维度进行小计。
select id , sku_id,sum(total_amount) from  t_order_mt group by id,sku_id with cube;
 
// with totals: 只计算合计。
select id , sku_id,sum(total_amount) from  t_order_mt group by id,sku_id with totals;
alter操作
// ALTER只支持MergeTree系列,Merge和Distributed引擎的表,基本语法:ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|MODIFY COLUMN ...
 
// 参数解析:
   ADD COLUMN – 向表中添加新列
   DROP COLUMN – 在表中删除列
   MODIFY COLUMN – 更改列的类型
 
// 案例演示:
   新增字段:alter table tableName  add column  newcolname  String after col1
   修改字段类型:alter table tableName  modify column  newcolname  String;
   删除字段:alter table tableName  drop column  newcolname;
describe table
// 查看表结构
hadoop102 :) desc dis_table;
DESCRIBE TABLE dis_table
┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ id   │ UInt16 │              │                    │         │                  │                │
│ name │ String │              │                    │         │                  │                │
└──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
2 rows in set. Elapsed: 0.001 sec.
ClickHouse数据压缩
通用编码
  • None:无压缩
  • LZ4:默认的压缩算法,缺省值也是使用默认的压缩算法
  • LZ4HC[(level)]:z4高压缩率压缩算法版本, level默认值为9,支持[112],推荐选用[49]
  • ZSTD[(level)]:zstd压缩算法,level默认值为1,支持[1~22]
特殊编码
  • LowCardinality:枚举值小于1w的字符串
  • Delta:时间序列类型的数据,不会对数据进行压缩
  • T64:比较适合Int类型数据
  • DoubleDelta:适用缓慢变化的序列:比如时间序列,对于递增序列效果很好
  • Gorilla:使用缓慢变化的数值类型

特殊编码与通用的压缩算法相比,区别在于,通用的LZ4和ZSTD压缩算法是普适行的,不关心数据的分布特点,而特殊编码类型对于特定场景下的数据会有更好的压缩效果。

使用

压缩算法和特殊编码两者可以结合起来一起使用

CREATE TABLE k19_ods.test8 (
    `found _time` Uint32,
    `recv_timet` UInt32 CODEC ( NONE ),
    `recv_time2` UInt32,
    `recv_time3` Ulnt32 CODEC ( LZ4 ),
    `recv_time4` UInt32 CODEC (LZ4HC ( 9 )),
    `recv_time5` UInt32 CODEC (ZSTD ( 9 ),
    `recv_time6` Ulnt32 CODEC ( T640 ),
    `name0` String CODEC (Delta (, LZ4 ),
    `name1` String CODEC ( DoubleDelta0 )),
    `name2` String CODEC ( Gorilla ( 0 ), 
    `name4` String cODEC ( Gorilla ), Lz4 ) 
    ) ENGINE = MergeTree () PARTITION BYtoYYYYMMDD ( toDateTime(found_time )) 
ORDER BY
    found_time
压缩效果对比

对于LZ4HC和ZSTD选择的压缩level越高,压缩效果越好,但是CPU的使用率也会相应的越高。如果插入的数据量很大,会明显看到较高的CPU使用率。

ClickHouse索引

clickhouse的索引由于其存储引擎的设计,可以做的非常简单。主要有一级索引和标记组成。一级索引实现数据到block的映射,标记实现block到文件偏移量的实现。另外,由于一级索引非常小,1亿条数据只需要1万多行的索引,因此一级索引可以常驻内存,加速查找。

同时,clickhouse还提供了二级索引,不过二级索引比较简单,且不是必须的,对整体性能影响也不大。

稀疏索引

首先,clickhouse的一级索引使用了一种叫做稀疏索引的技术,那么何为稀疏索引呢?既然有稀疏索引,是不是相对的也有稠密索引呢?没错,确实有。二者的区别如下:
稠密索引: 每行数据记录都会对应一行索引标记。
稀疏索引: 每隔若干行记录对应一条索引标记。
既然概念清楚了,那么使用稀疏索引带来的好处也是显而易见的,那就是可以大幅减少索引占用的空间。以clcikhouse默认的索引力度8192为例,1亿行数据只需要存储12208行索引。因为占用空间小,clickhouse中一级索引的数据是常驻内存的,所以取用速度极快。
那么稠密索引也有其好处,因为每条记录都有索引,所以查询的时候可以一步到位,当然缺点就是会占用较多的空间,像mysql的主键索引即是使用的稠密索引。

索引粒度

索引粒度对应的是index_granularity这个参数,前一节我们已经说了clickhouse使用的是稀疏索引的方式,那么index_granulariy这个参数就是决定每隔多上行数据生成一条索引记录了,默认是8192,新版本的clickhouse已经提供了自适应粒度大小的特性。

索引文件

clickhouse会在每个分区目录下生成一个索引文件primary.idx,记录了主键排序后按照索引粒度采样的值,以二进制的方式存储,可以通过od命令进行查看:

[root@slave3 20201216_22_22_0]# od -l -j 0 -N 80 --width=8 primary.idx
0000000     1608087600001562
0000010     1608087966741501
0000020     1608087637579224
0000030     1608088172094313
0000040     1608087674594699
0000050     1608087862362366
0000060     1608087712835091
0000070     1608087875942332
0000100     1608087750685288
0000110     1608088251777291
0000120
标记文件

因为是稀疏索引,所以显然只靠一级索引文件是无法精确定位到数据的,这时候就需要标记文件登场了。在分区目录下,你可以看到很多后缀为.bin和.mrk2的文件,其中.bin是真实的数据内容,.mrk2就是我们要说的标记文件。因为clickhouse底层是按列进行存储的,因此每一列会对应一个.bin文件和.mrk2文件。

[root@slave3 20201216_22_22_0]# od -l -j 0 -N 240 --width=24 ./city.mrk2
0000000                    0                    0                 8192
0000030                    0                32768                 8192
0000060                  295                    0                 8192
0000110                  295                32768                 8192
0000140                  590                    0                 8192
0000170                  590                32768                 8192
0000220                  885                    0                 8192
0000250                  885                32768                 8192
0000300                  885                64680                    0
0000330

一行标记数据使用一个元组表示,元组内包含数据压缩块位置(在.bin文件中数据是切分成若干个数据块压缩存储的),数据块内偏移和索引粒度的大小。
标记文件并不能常驻内存,俄日是使用LRU缓存策略加快其读取速度。

索引工作方式

clickhouse是如何利用primary.idx和.mr2文件检索到具体的文件内容的呢?首先索引文件和标记文件在行上是对齐的,从上面索引文件和标记文件的示例可以看出来,二者的行数是一样的,如图:

ClickHouse基础知识及与MySQL性能对比_第3张图片

在查询的时候,会先根据要索引的值或范围,在primary.idx文件中确定一个行号范围(具体确定的过程这里就不详细展开了,基本上就是一个递归交集的判断),然后按照相同的行号范围在每一列的.mrk中查询,得到要查询的值在数据文件.bin的哪一个压缩块,以及将该压缩块解压之后在什么位置,然后将查询到的数据结果返回。

通过partition + 一级索引 + 标记文件,层层缩小数据扫描范围,clickhouse达到了其快速检索的目的。

疑问:上面所说的都是查询条件命中索引的情况,如果没有的话clickhouse是怎么处理的呢?
当然只能是每个partition挨个扫描了,不过因为.bin文件分了若干个小的压缩块,clickhouse利用多线程读取压缩块的方式在一定程度上也可以加速查找过程。

ClickHouse性能
单个查询吞吐量

如果数据被放置在page cache中,则一个不太复杂的查询在单个服务器上大约能够以2-10GB/s(未压缩)的速度进行处理(对于简单的查询,速度可以达到30GB/s)。如果数据没有在page cache中的话,那么速度将取决于你的磁盘系统和数据的压缩率。例如,如果一个磁盘允许以400MB/s的速度读取数据,并且数据压缩率是3,则数据的处理速度为1.2GB/s。这意味着,如果你是在提取一个10字节的列,那么它的处理速度大约是1-2亿行每秒。对于分布式处理,处理速度几乎是线性扩展的,但这受限于聚合或排序的结果不是那么大的情况下。

处理短查询的延时时间

数据被page cache缓存的情况下,它的延迟应该小于50毫秒(最佳情况下应该小于10毫秒)。 否则,延迟取决于数据的查找次数。延迟可以通过以下公式计算得知: 查找时间(10 ms) * 查询的列的数量 * 查询的数据块的数量。

处理大量短查询

ClickHouse可以在单个服务器上每秒处理数百个查询(在最佳的情况下最多可以处理数千个)。但是由于这不适用于分析型场景。建议每秒最多查询100次。

数据写入性能

建议每次写入不少于1000行的批量写入,或每秒不超过一个写入请求。当使用tab-separated格式将一份数据写入到MergeTree表中时,写入速度大约为50到200MB/s。如果您写入的数据每行为1Kb,那么写入的速度为50,000到200,000行每秒。如果您的行更小,那么写入速度将更高。为了提高写入性能,您可以使用多个INSERT进行并行写入,这将带来线性的性能提升。

count: 千万级别,500毫秒,1亿 800毫秒 2亿 900毫秒 3亿 1.1秒
group: 百万级别 200毫米,千万 1秒,1亿 10秒,2亿 20秒,3亿 30秒
join:千万-10万 600 毫秒, 千万 -百万:10秒,千万-千万 150秒

通过insert语句逐条插入的方法性能最差,且对于MergeTree表引擎来说,在大数据量写入的情况下该方法会触发频繁的后台文件合并,甚至会出现“too many parts”的错误。

mysql与ClickHouse性能写入区别?

mysql:

(1)MySQL单条SQL是单线程的,只能跑满一个core
(2)IO方面,MySQL是行存储,MySQL需要大量随机IO

ClickHouse:

(1)ClickHouse相反,有多少CPU,吃多少资源,所以飞快
(2)ClickHouse不支持事务,不存在隔离级别。ClickHouse的定位是分析性数据库,而不是严格的关系型数据库
(3)IO方面,ClickHouse是列存储,后者在count()这类操作天然有优势,ClickHouse基本是顺序IO

springboot、mybatis-plus及ClickHouse整合
依赖


	ru.yandex.clickhouse
	clickhouse-jdbc
	0.3.2



	com.alibaba
	druid
	1.1.21



	com.baomidou
	mybatis-plus-boot-starter
	3.4.0

配置

application.yml 配置:SpringBoot默认是不注入 clickhouse属性值的,需要自己绑定。

spring:
  datasource:
    # 数据源选择
    type: com.alibaba.druid.pool.DruidDataSource
    # clickhouse配置
    click:
      driverClassName: ru.yandex.clickhouse.ClickHouseDriver
      url: jdbc:clickhouse://127.0.0.1:8123/default
      username: default
      password:
      initialSize: 10
      maxActive: 100
      minIdle: 10
      maxWait: 6000

Bean配置:用了druid监控所以在这里边初始化了,这个 DataSource 也可以在启动类里初始化。

@Configuration
public class DruidConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.click")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
}
使用注意点
  • entity中对于Date类型的字段要使用@JsonFormat格式化日期字符串。
  • 删除和修改的SQL需要自己重写
-- 删除语法
alter table table_name delete WHERE primary_key='10';

-- 修改语法
alter table tb_stattable_name update cloumn1=222 WHERE primary_key = '4';
  • 无法使用mybatis-plus-generator生成代码
mysql数据迁移ClickHouse
ClickHouse同步建表
create table engine mysql

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster](
 name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
 name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
 ...
 INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
 INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MySQL('host:port', 'database', 'table', 'user', 'password'[, replace_query, 'on_duplicate_clause']);

注意,实际数据存储在远端mysql数据库中,可以理解成外表。

建表语句
CREATE TABLE ${表名} ENGINE = MergeTree ORDER BY ${主键名} AS 
SELECT * FROM mysql('${MySql的IP:PORT}', 'MySql的数据库名', 'MySql的表名', 'MySql的用户名', 'MySql的密码');

重要: 1: MySQL的必需有主键且不能为空

2: ORDER BY 后的字段大小写要和MySQL的大小写一样

3: 需要注意的是建表的时候需要注意两边的字段类型,特别是MySql的Decimal的类型,ClickHouse建表需要注意更改为 Float64 类型。

字段映射表:

ClickHouse MySQL Comment
UInt8, UInt16, UInt32, UInt64 TINYINT UNSIGNED, SMALLINT UNSIGNED, INT UNSIGNED, BIGINT UNSIGNED
Int8, Int16, Int32, Int64 TINYINT SIGNED, SMALLINT SIGNED, INT SIGNED, BIGINT SIGNED
Float32, Float64 FLOAT, DOUBLE Supports inf, -inf, nan, recommended NOT to use by ClickHouse!
String BLOB, TEXT, VARCHAR, VARBINARY No encoding. Recommended to use UTF-8. In fact behaves like a BLOB.
FixedString(n) CHAR, BINARY \0 padded. Less functions available than String, in fact it behaves like BINARY.
Date DATE UNIX epoch date up to 2038.
DateTime DATETIME, TIMESTAMP UNIX epoch timestamp up to 2038.
Enum ENUM Similar to MySQL ENUM. Behaves like Int8/16.
Array(type) n.a. Array of type. Closest equivalent in MySQL is JSON? Not well supported.
Tuple() n.a.
Nested() n.a. Closest equivalent in MySQL is JSON?
AggregateFunction() n.a.
Set n.a.
Expression n.a.
ClickHouse待解决问题
  • ClickHouse过度依赖大宽表。对于任何数据分析的场景,都需要把相关数据放在一起,提前做成大宽表。先不说提前做大宽表带来的工作量,无法支持好星型模型和雪花模型,将极大限制了分析业务数据的能力。想一想为了构建和维护大宽表所耗费的精力,再想一想把维度表数据和海量事实表关联后产生的数据冗余,确实为了高查询性能付出了很多额外的成本。如果业务还需要对某些维度列进行经常性的更新,那可能真的是一个大麻烦。还需提醒业务分析人员注意SQL写法,标准SQL有时候根本跑不动。
  • ClickHouse难以支持高并发的业务场景。数据分析系统只能同时提供给少数人使用。如果需要支持的业务分析人员比较多,只能不断地搭建新的集群。
  • ClickHouse集群的运维复杂度一定曾让人感到头疼。需要依赖第三方系统来运行副本机制;需要在配置文件中维护所有服务器的信息;扩缩容时需要创建新表重新导数据;如果数据量增大,数据表数增多,Zookeeper就会形成性能的瓶颈,甚至会出现元数据不一致的问题。
  • 遇到过出现线上问题,但是找不到及时和靠谱技术支持的窘境。作为支撑公司业务发展的数据分析系统,无法提供服务就意味着管理层的决策和业务人员的工作都陷入了盲目的状态,这很有可能会影响到公司的业务发展,也可能会影响职业发展。

你可能感兴趣的:(数据库,sql)