ClickHouse学习

第 1 章 ClickHouse 入门

ClickHouse 是俄罗斯的 Yandex 于 2016 年开源的列式存储数据库(DBMS),使用 C++ 语言编写,主要用于在线分析处理查询(OLAP),能够使用 SQL 查询实时生成分析数据报告。

1.1 ClickHouse 的特点

1.1.1 列式存储

以下面的表为例:

Id Name Age
1 张三 18
2 李四 22
3 王五 34
1)采用行式存储时,数据在磁盘上的组织结构为:

在这里插入图片描述

好处是想查某个人所有的属性时,可以通过一次磁盘查找加顺序读取就可以。但是当想查所有人的年龄时,需要不停的查找,或者全表扫描才行,遍历的很多数据都是不需要的。

2)采用列式存储时,数据在磁盘上的组织结构为:

在这里插入图片描述

这时想查所有人的年龄只需把年龄那一列拿出来就可以了

3)列式储存的好处:
  • 对于列的聚合,计数,求和等统计操作优于行式存储。
  • 由于某一列的数据类型都是相同的,针对于数据存储更容易进行数据压缩,每一列选择更优的数据压缩算法,大大提高了数据的压缩比重。
  • 由于数据压缩比更好,一方面节省了磁盘空间,另一方面对于 cache 也有了更大的发挥空间。

1.1.2 DBMS 的功能

几乎覆盖了标准 SQL 的大部分语法,包括 DDL 和 DML,以及配套的各种函数,用户管理及权限管理,数据的备份与恢复。

1.1.3 多样化引擎

ClickHouse 和 MySQL 类似,把表级的存储引擎插件化,根据表的不同需求可以设定不同的存储引擎。目前包括合并树、日志、接口和其他四大类 20 多种引擎。

1.1.4 高吞吐写入能力

ClickHouse 采用类 LSM Tree 的结构,数据写入后定期在后台 Compaction。通过类 LSM tree 的结构,ClickHouse 在数据导入时全部是顺序 append 写,写入后数据段不可更改,在后台 compaction 时也是多个段 merge sort 后顺序写回磁盘。顺序写的特性,充分利用了磁盘的吞吐能力,即便在 HDD 上也有着优异的写入性能。

官方公开 benchmark 测试显示能够达到 50MB-200MB/s 的写入吞吐能力,按照每行100Byte 估算,大约相当于 50W-200W 条/s 的写入速度。

1.1.5 数据分区与线程级并行

ClickHouse 将数据划分为多个 partition,每个 partition 再进一步划分为多个 index granularity(索引粒度),然后通过多个 CPU 核心分别处理其中的一部分来实现并行数据处理。在这种设计下,单条 Query 就能利用整机所有 CPU。极致的并行处理能力,极大的降低了查询延时。

所以,ClickHouse 即使对于大量数据的查询也能够化整为零平行处理。但是有一个弊端就是对于单条查询使用较多 cpu,就不利于同时并发多条查询。所以对于高 qps 的查询业务,ClickHouse 并不是强项。

1.1.6 性能对比

1)单表查询

ClickHouse学习_第1张图片

2)关联查询

ClickHouse学习_第2张图片
结论: ClickHouse 像很多 OLAP 数据库一样,单表查询速度优于关联查询,而且 ClickHouse 的两者差距更为明显。

第 2 章 ClickHouse 的安装

2.1 准备工作

2.1.1 确定防火墙处于关闭状态

# 查看防火墙状态
systemctl status firewalld

# 关闭防火墙
systemctl stop firewalld

2.1.2 CentOS 取消打开文件数限制

(1)查看文件数限制

ulimit -a

ClickHouse学习_第3张图片

(2)在 /etc/security/limits.conf 文件的末尾加入以下内容

# soft指当前数值,hard指最大数值
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072

(3)在 /etc/security/limits.d/20-nproc.conf 文件的末尾加入以下内容

* soft nproc 131072
* hard nproc 131072

(4)在 /etc/security/limits.d/20-nofile.conf 文件的末尾加入以下内容

* soft nofile 65536
* hard nofile 65536

(5)重新登录即可生效

2.1.3 安装依赖

sudo yum install -y libtool
sudo yum install -y *unixODBC*

2.1.4 CentOS 取消 SELINUX

(1)修改/etc/selinux/config 中的 SELINUX=disabled

SELINUX=disabled

(2)临时关闭 SELINUX

# 查看SELINUX状态
getenforce
# 关闭SELINUX
setenforce 0

2.2 单机安装

官方网址:https://clickhouse.com/

下载地址:https://packages.clickhouse.com/rpm/stable/

2.2.1 在 /opt/software 下创建 clickhouse 目录

cd /opt/software/
mkdir clickhouse

2.2.2 将 ClickHouse 安装文件上传到 clickhouse 目录下

2.2.3 安装

# 安装
sudo rpm -ivh *.rpm
# 查看安装情况
sudo rpm -qa|grep clickhouse

2.2.4 修改配置文件

sudo vim /etc/clickhouse-server/config.xml

(1)把 :: 的注释打开,这样的话才能让 ClickHouse 被除本机以外的服务器访问

注意:生产环境可以配置指定的IP进行访问

(2)默认的路径配置

数据文件路径:<path>/</path>

日志文件路径:<log>/var/log/clickhouse-server/clickhouse-server.log</log>

2.2.5 启动 Server

sudo systemctl start clickhouse-server

2.2.6 关闭开机自启(可选)

sudo systemctl disable clickhouse-server

2.2.7 使用 client 连接 server

clickhouse-client -m [--password]

第 3 章 数据类型

3.1 整型

固定长度的整型,包括有符号整型或无符号整型。

整型范围(-2n-1~2n-1-1):

Int8 - [-128 : 127]

Int16 - [-32768 : 32767]

Int32 - [-2147483648 : 2147483647]

Int64 - [-9223372036854775808 : 9223372036854775807]

无符号整型范围(0~2n-1):

UInt8 - [0 : 255]

UInt16 - [0 : 65535]

UInt32 - [0 : 4294967295]

UInt64 - [0 : 18446744073709551615]

3.2 浮点型

Float32 - float

Float64 – double
ClickHouse学习_第4张图片

注意:浮点型在进行计算时可能会引起四舍五入的误差。

3.3 布尔型

没有单独的类型来存储布尔值。可以使用 UInt8 类型,取值限制为 0 或 1。

3.4 Decimal 型

有符号的浮点数,可在加、减和乘法运算过程中保持精度。对于除法,最低有效数字会被丢弃(不舍入)。

有三种声明:

  • Decimal32(s),相当于 Decimal(9-s, s),有效位数为 1~9
  • Decimal64(s),相当于 Decimal(18-s, s),有效位数为 1~18
  • Decimal128(s),相当于 Decimal(38-s, s),有效位数为 1~38
    s 标识小数位

3.5 字符串

1)String

字符串可以任意长度的。它可以包含任意的字节集,包含空字节。

2)FixedString(N)

固定长度 N 的字符串,N 必须是严格的正自然数。当服务端读取长度小于 N 的字符串时候,通过在字符串末尾添加空字节来达到 N 字节长度。 当服务端读取长度大于 N 的字符串时候,将返回错误消息。

与 String 相比,极少会使用 FixedString,因为使用起来不是很方便。

3.6 枚举类型

包括 Enum8 和 Enum16 类型。Enum 保存 ‘string’= integer 的对应关系。

Enum8 用 ‘String’= Int8 对描述。

Enum16 用 ‘String’= Int16 对描述。

1)用法演示

创建一个带有一个枚举 Enum8(‘hello’ = 1, ‘world’ = 2) 类型的列

CREATE TABLE t_enum
(
    `x` Enum8('hello' = 1, 'world' = 2)
)
ENGINE = TinyLog;

2)这个 x 列只能存储类型定义中列出的值:’hello’或’world’

INSERT INTO t_enum VALUES ('hello'), ('world'), ('hello');

ClickHouse学习_第5张图片

3)如果尝试保存任何其他值,ClickHouse 抛出异常

INSERT INTO t_enum VALUES('a');

ClickHouse学习_第6张图片

4)如果需要看到对应行的数值,则必须将 Enum 值转换为整数类型

SELECT CAST(x, 'Int8') FROM t_enum;

ClickHouse学习_第7张图片

3.7 时间类型

目前 ClickHouse 有三种时间类型

  • Date 接受年-月-日的字符串比如 ‘2019-12-16’
  • Datetime 接受年-月-日 时:分:秒的字符串比如 ‘2019-12-16 20:50:10’
  • Datetime64 接受年-月-日 时:分:秒.亚秒的字符串比如 ‘2019-12-16 20:50:10.66’
    日期类型,用两个字节存储,表示从 1970-01-01 (无符号) 到当前的日期值。

3.8 数组

Array(T):由 T 类型元素组成的数组。

T 可以是任意类型,包含数组类型。但不推荐使用多维数组,ClickHouse 对多维数组的支持有限。例如,不能在 MergeTree 表中存储多维数组。

(1)创建数组方式 1,使用 array 函数

ClickHouse学习_第8张图片

(2)创建数组方式 2:使用方括号

ClickHouse学习_第9张图片

第 4 章 表引擎

4.1 表引擎的使用

表引擎是 ClickHouse 的一大特色。可以说,表引擎决定了如何存储表的数据。包括:

  • 数据的存储方式和位置,写到哪里以及从哪里读取数据。
  • 支持哪些查询以及如何支持。
  • 并发数据访问。
  • 索引的使用(如果存在)。
  • 是否可以执行多线程请求。
  • 数据复制参数。

表引擎的使用方式就是必须显式在创建表时定义该表使用的引擎,以及引擎使用的相关参数。

特别注意:引擎的名称大小写敏感

4.2 TinyLog

以列文件的形式保存在磁盘上,不支持索引,没有并发控制。一般保存少量数据的小表,生产环境上作用有限。

CREATE TABLE t_tinylog
(
    `id` String,
    `name` String
)
ENGINE = TinyLog;

4.3 Memory

内存引擎,数据以未压缩的原始形式直接保存在内存当中,服务器重启数据就会消失。读写操作不会相互阻塞,不支持索引。简单查询下有非常非常高的性能表现(超过 10G/s)。

4.4 MergeTree

ClickHouse 中最强大的表引擎当属 MergeTree(合并树)引擎及该系列(*MergeTree)中的其他引擎,支持索引和分区,地位可以相当于 innodb 之于 Mysql。

1)建表语句

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);

2)插入数据

INSERT INTO t_order_mt VALUES
(101,'sku_001',1000.00,'2020-06-01 12:00:00') ,
(102,'sku_002',2000.00,'2020-06-01 11:00:00'),
(102,'sku_004',2500.00,'2020-06-01 12:00:00'),
(102,'sku_002',2000.00,'2020-06-01 13:00:00'),
(102,'sku_002',12000.00,'2020-06-01 13:00:00'),
(102,'sku_002',600.00,'2020-06-02 12:00:00');

MergeTree 其实还有很多参数(绝大多数用默认值即可),但是这三个参数是更加重要的,也涉及了关于 MergeTree 的很多概念。

4.4.1 partition by 分区(可选)

1)作用

分区的目的主要是降低扫描的范围,优化查询速度

2)如果不填

只会使用一个分区。

3)分区目录

MergeTree 是以列文件+索引文件+表定义文件组成的,但是如果设定了分区那么这些文件就会保存到不同的分区目录中。

分区目录文件命名规则:PartitionId_MinBlockNum_MaxBlockNum_Level(分区值_最小分区_最大分区块编号_合并层级)

  • PartitionId:
    数据分区 ID 生成规则
    数据分区规则由分区 ID 决定,分区ID由 PARTITION BY 分区键决定。根据分区键字段类型,ID生成规则可以分为:
    未定义分区键:没有定义 PARTITION BY ,默认生成一个目录名为 all 的数据分区,所有数据均存放在 all 目录下。
    整型分区键:分区键为整型,那么直接用该整型值的字符串形式作为分区ID。
    日期类分区键:分区键为日期类型,或者可以转化成日期类型。
    其他类型分区键:String、Float 类型等,通过128位的 Hash 算法取其 Hash 值作为分区ID。
  • MinBlockNum:最小分区块编号,自增类型,从1开始向上递增。每产生一个新的目录分区就向上递增一个数字。
  • MaxBlockNum:最大分区块编号,新创建的分区 MinBlockNum 等于 MaxBlockNum 的编号。
  • Level:合并的层级,被合并的次数。合并次数越多,层级值越大。
    4)并行

分区后,面对涉及跨分区的查询统计,ClickHouse 会以分区为单位并行处理。

5)数据写入与分区合并

任何一个批次的数据写入都会产生一个临时分区,不会纳入任何一个已有的分区。写入后的某个时刻(大概 10-15 分钟后),ClickHouse 会自动执行合并操作(等不及也可以手动通过 optimize 执行),把临时分区的数据,合并到已有分区中。

OPTIMIZE TABLE xxxx FINAL;
# 只针对某一个分区做合并操作
OPTIMIZE TABLE xxxx PARTITION 'yyyy' FINAL;

4.4.2 primary key 主键(可选)

ClickHouse 中的主键,和其他数据库不太一样,它只提供了数据的一级索引,但是却不是唯一约束。这就意味着是可以存在相同 primary key 的数据的。

主键的设定主要依据是查询语句中的 where 条件。

根据条件通过对主键进行某种形式的二分查找,能够定位到对应的 index granularity,避免了全表扫描。

index granularity:直接翻译的话就是索引粒度,指在稀疏索引中两个相邻索引对应数据的间隔。ClickHouse 中的 MergeTree 默认是 8192。官方不建议修改这个值,除非该列存在大量重复值,比如在一个分区中几万行才有一个不同数据。

稀疏索引:
ClickHouse学习_第10张图片

稀疏索引的好处就是可以用很少的索引数据,定位更多的数据,代价就是只能定位到索引粒度的第一行,然后再进行进行一点扫描。

4.4.3 order by(必选)

order by 设定了分区内的数据按照哪些字段顺序进行有序保存。

order by 是 MergeTree 中唯一一个必填项,甚至比 primary key 还重要,因为当用户不设置主键的情况,很多处理会依照 order by 的字段进行处理。

要求:主键必须是 order by 字段的前缀字段。

比如 order by 字段是 (id, sku_id) 那么主键必须是 id 或者(id, sku_id)

4.4.4 二级索引

目前在 ClickHouse 的官网上二级索引的功能在 v20.1.2.4 之前是被标注为实验性的,在这个版本之后默认是开启的。

1)老版本使用二级索引前需要增加设置

set allow_experimental_data_skipping_indices=1;

2)创建测试表

CREATE TABLE t_order_mt2
(
    `id` UInt32,
    `sku_id` String,
    `total_amount` Decimal(16, 2),
    `create_time` Datetime,
    INDEX a total_amount TYPE minmax GRANULARITY 5
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(create_time)
PRIMARY KEY id
ORDER BY (id, sku_id);

其中 GRANULARITY N 是设定二级索引对于一级索引粒度的粒度。

3)插入数据

INSERT INTO t_order_mt2 VALUES
(101, 'sku_001', 1000.00, '2020-06-01 12:00:00') ,
(102, 'sku_002', 2000.00, '2020-06-01 11:00:00'),
(102, 'sku_004', 2500.00, '2020-06-01 12:00:00'),
(102, 'sku_002', 2000.00, '2020-06-01 13:00:00'),
(102, 'sku_002', 12000.00, '2020-06-01 13:00:00'),
(102, 'sku_002', 600.00, '2020-06-02 12:00:00');

4)对比效果

使用下面语句进行测试,可以看出二级索引能够为非主键字段的查询发挥作用。

clickhouse-client [--password] --send_logs_level=trace <<< 'select * from t_order_mt2 where total_amount > toDecimal32(900., 2)';

4.4.5 数据 TTL

TTL 即 Time To Live,MergeTree 提供了可以管理数据表或者列的生命周期的功能。

1)列级别 TTL

(1)创建测试表

CREATE TABLE t_order_mt3
(
    `id` UInt32,
    `sku_id` String,
    `total_amount` Decimal(16, 2) TTL create_time + INTERVAL 10 SECOND,
    `create_time` Datetime
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(create_time)
PRIMARY KEY id
ORDER BY (id, sku_id);

(2)插入数据

INSERT INTO t_order_mt3 VALUES
(106, 'sku_001', 1000.00, NOW()),
(107, 'sku_002', 2000.00, NOW()),
(110, 'sku_003', 600.00, NOW() + INTERVAL 10 SECOND);

(3)手动合并,查看效果,到期后,指定的字段数据将变为默认值
ClickHouse学习_第11张图片

官方文档:When the values in the column expire, ClickHouse replaces them with the default values for the column data type. If all the column values in the data part expire, ClickHouse deletes this column from the data part in a filesystem.
但是实际测试下来,每个分区的最新的一条或多条数据不会被删除,原因未知。

2)表级 TTL

下面的这条语句是数据会在 create_time 之后 10 秒丢失

ALTER TABLE t_order_mt3 MODIFY TTL create_time + INTERVAL 10 SECOND;

涉及判断的字段必须是 Date 或者 Datetime 类型,推荐使用分区的日期字段。

能够使用的时间周期:

  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • WEEK
  • MONTH
  • QUARTER
  • YEAR

4.5 ReplacingMergeTree

ReplacingMergeTree 是 MergeTree 的一个变种,它存储特性完全继承 MergeTree,只是多了一个去重的功能。 尽管 MergeTree 可以设置主键,但是 primary key 其实没有唯一约束的功能。如果你想处理掉重复的数据,可以借助这个 ReplacingMergeTree。

1)去重时机

数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,所以你无法预先作出计划。有一些数据可能仍未被处理。

2)去重范围

如果表经过了分区,去重只会在分区内部进行去重,不能执行跨分区的去重。

所以 ReplacingMergeTree 能力有限, ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

3)案例演示

(1)创建表

CREATE TABLE t_order_rmt
(
    `id` UInt32,
    `sku_id` String,
    `total_amount` Decimal(16, 2),
    `create_time` Datetime
)
ENGINE = ReplacingMergeTree(create_time)
PARTITION BY toYYYYMMDD(create_time)
PRIMARY KEY id
ORDER BY (id, sku_id);

ReplacingMergeTree() 填入的参数为版本字段,重复数据保留版本字段值最大的。

如果不填版本字段,默认按照插入顺序保留最后一条。

(2)向表中插入数据

INSERT INTO t_order_rmt VALUES
(101, 'sku_001', 1000.00, '2020-06-01 12:00:00'),
(102, 'sku_002', 2000.00, '2020-06-01 11:00:00'),
(102, 'sku_004', 2500.00, '2020-06-01 12:00:00'),
(102, 'sku_002', 2000.00, '2020-06-01 13:00:00'),
(102, 'sku_002', 12000.00, '2020-06-01 13:00:00'),
(102, 'sku_002', 600.00, '2020-06-02 12:00:00');

(3)重复再插入一次,执行第一次查询

SELECT * FROM t_order_rmt;

ClickHouse学习_第12张图片

(4)手动合并

OPTIMIZE TABLE t_order_rmt FINAL;

ClickHouse学习_第13张图片

(5)再执行一次查询

SELECT * FROM t_order_rmt;

4)通过测试得到结论

  • 实际上是使用 order by 字段作为唯一键
  • 去重不能跨分区
  • 只有同一批插入(新版本)或合并分区时才会进行去重
  • 认定重复的数据保留,取版本字段值最大的
  • 如果版本字段相同则按插入顺序保留最后一笔

4.6 SummingMergeTree

对于不查询明细,只关心以维度进行汇总聚合结果的场景。如果只使用普通的MergeTree的话,无论是存储空间的开销,还是查询时临时聚合的开销都比较大。

ClickHouse 为了这种场景,提供了一种能够“预聚合”的引擎 SummingMergeTree

1)案例演示

(1)创建表

CREATE TABLE t_order_smt
(
    `id` UInt32,
    `sku_id` String,
    `total_amount` Decimal(16, 2),
    `create_time` Datetime
)
ENGINE = SummingMergeTree(total_amount)
PARTITION BY toYYYYMMDD(create_time)
PRIMARY KEY id
ORDER BY (id, sku_id);

(2)插入数据

INSERT INTO t_order_smt VALUES
(101, 'sku_001', 1000.00, '2020-06-01 12:00:00'),
(102, 'sku_002', 2000.00, '2020-06-01 11:00:00'),
(102, 'sku_004', 2500.00, '2020-06-01 12:00:00'),
(102, 'sku_002', 2000.00, '2020-06-01 13:00:00'),
(102, 'sku_002', 12000.00, '2020-06-01 13:00:00'),
(102, 'sku_002', 600.00, '2020-06-02 12:00:00');

(3)重复再插入一次,执行第一次查询

SELECT * FROM t_order_smt;

ClickHouse学习_第14张图片

(4)手动合并

OPTIMIZE TABLE t_order_smt FINAL;

ClickHouse学习_第15张图片

2)通过结果可以得到以下结论

  • 以 SummingMergeTree()中指定的列作为汇总数据列
  • 可以填写多列必须数字列,如果不填,以所有非维度列且为数字列的字段为汇总数据列
  • 以 order by 的列为准,作为维度列
  • 其他的列按插入顺序保留第一行
  • 不在一个分区的数据不会被聚合
  • 只有在同一批次插入(新版本)或分片合并时才会进行聚合
    3)开发建议

设计聚合表的话,唯一键值、流水号可以去掉,所有字段全部是维度、度量或者时间戳。

4)问题

能不能直接执行以下 SQL 得到汇总值

SELECT total_amount FROM XXX WHERE province_name = '' AND create_date = 'xxx'

不行,可能会包含一些还没来得及聚合的临时明细

如果要是获取汇总值,还是需要使用 sum 进行聚合,这样效率会有一定的提高,但本身 ClickHouse 是列式存储的,效率提升有限,不会特别明显。

SELECT SUM(total_amount) FROM XXX WHERE province_name = '' AND create_date = 'xxx'

第 5 章 SQL 操作

基本上来说传统关系型数据库(以 MySQL 为例)的 SQL 语句,ClickHouse 基本都支持,这里只介绍 ClickHouse 与标准 SQL(MySQL)不一致的地方。

5.1 Insert

与标准 SQL(MySQL)基本一致

(1)标准

INSERT INTO [table_name] VALUES (...), (...)

(2)从表到表的插入

INSERT INTO [table_name] SELECT a,b,c FROM [table_name_2]

5.2 Update 和 Delete

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

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

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

(1)删除操作

ALTER TABLE t_order_smt DELETE WHERE sku_id = 'sku_001';

(2)修改操作

ALTER TABLE t_order_smt UPDATE total_amount = toDecimal32(2000.00, 2) WHERE id = 102;

由于操作比较“重”,所以 Mutation 语句分两步执行,同步执行的部分其实只是进行新增数据新增分区和并把旧分区打上逻辑上的失效标记。直到触发分区合并的时候,才会删除旧数据释放磁盘空间,一般不会开放这样的功能给用户,由管理员完成。

问题:如何实现高性能 update 和 delete ?

回答:在创建表时,添加两个标记字段,如下所示:

CREATE TABLE A
(
	a xxx,
    b xxx,
    c xxx,
    _sign UInt8,
    _version UInt32
)

那么,对于更新操作,则相当于是插入一条新的数据,此时 _version + 1,查询的时候加上一个过滤条件(WHERE _version最大)进行查询。

对于删除操作,通过 _sign(0表示未删除,1表示已删除),同时 _version + 1,查询的时候加上一个过滤条件(WHERE _sign = 0 AND _version最大)进行查询。

那么如果时间久了,数据膨胀了怎么办?可以提供类似合并的机制,定期把过期数据进行清除。

5.3 查询操作

ClickHouse 基本上与标准 SQL 差别不大

  • 支持子查询
  • 支持 CTE(Common Table Expression 公用表表达式 with 子句)
  • 支持各种 JOIN,但是 JOIN 操作无法使用缓存,所以即使是两次相同的 JOIN 语句,ClickHouse 也会视为两条新 SQL
  • 支持窗口函数
  • 支持自定义函数
  • GROUP BY 操作增加了 with rollup\with cube\with total 用来计算小计和总计。
    (1)插入数据
-- 清空数据
ALTER TABLE t_order_mt DELETE WHERE 1 = 1;
-- 插入数据
INSERT INTO t_order_mt VALUES
(101,'sku_001',1000.00,'2020-06-01 12:00:00'),
(101,'sku_002',2000.00,'2020-06-01 12:00:00'),
(103,'sku_004',2500.00,'2020-06-01 12:00:00'),
(104,'sku_002',2000.00,'2020-06-01 12:00:00'),
(105,'sku_003',600.00,'2020-06-02 12:00:00'),
(106,'sku_001',1000.00,'2020-06-04 12:00:00'),
(107,'sku_002',2000.00,'2020-06-04 12:00:00'),
(108,'sku_004',2500.00,'2020-06-04 12:00:00'),
(109,'sku_002',2000.00,'2020-06-04 12:00:00'),
(110,'sku_003',600.00,'2020-06-01 12:00:00');

(2)with rollup:从右至左去掉维度进行小计

SELECT id, sku_id, sum(total_amount) FROM t_order_mt GROUP BY id, sku_id WITH ROLLUP;

ClickHouse学习_第16张图片

(3)with cube : 从右至左去掉维度进行小计,再从左至右去掉维度进行小计

SELECT id, sku_id, sum(total_amount) FROM t_order_mt GROUP BY id, sku_id WITH CUBE;

ClickHouse学习_第17张图片

(4)with totals: 只计算合计

SELECT id, sku_id, sum(total_amount) FROM t_order_mt GROUP BY id, sku_id WITH TOTALS;

ClickHouse学习_第18张图片

5.4 alter 操作

同 MySQL 的修改字段基本一致

1)新增字段

ALTER TABLE tableName ADD COLUMN newcolname String AFTER col1;

2)修改字段类型

ALTER TABLE tableName MODIFY COLUMN newcolname String;

3)删除字段

ALTER TABLE tableName DROP COLUMN newcolname;

5.5 导出数据

clickhouse-client --query "select * from t_order_mt where create_time='2020-06-01 12:00:00'" --format CSVWithNames> /opt/module/data/rs1.csv

更多支持格式参考:https://clickhouse.com/docs/en/interfaces/formats/

最后声明:该文章大部分内容转载自该博客网址:https://daiqiaohong.gitee.io/blog
文章写得很好,希望大家多多拜读。

你可能感兴趣的:(笔记,clickhouse,学习,数据库)