1.1什么是ClickHouse
ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告,C++语言编写的
OLAP
定位就是用于OLAP离线数据处理,相比较于OLTP在线事务处理,CK更关注于对海量数据的计算分析,关注的是数据吞吐、查询速度、计算机性能等指标。而对于数据频繁的修改变更,则不太擅长,所以CK通常用来构建后端的实时数仓或者离线速仓
1.2什么是列式存储
CK是真正意义上的列式存储数据库,传统数据库存储数据是按照数据行进行存储
行式存储:数据完整性
列式存储:相较于行式存储很多数据计算方面会体现很多优势
例如:通常一个计算过程都只会用到少数几个列的数据,这时行式存储就需要读取到相关行所有列数据在进行过滤,而列式存储就可以直接读取到这几个列的相关数据,而不用查找其他不关心的数据
适用场景:
一个典型的OLAP场景主要是对海量数据进行更新,相比较于常用的mysql等OLTP数据库有一些明显的特征
- 绝大多数请求都是读请求,对数据的修改比较少或者几乎没有
- 数据量很大,这个量既包括数据的行数,也包括数据的列数、也就是通常说的宽表。大部分情况下对分布式表结构的要求是必须的
- 数据通常以大的批次进行整体更新,而不是单行更新。这需要有很高的数据吞吐量。
- 对事物的要求不是必须的。对于数据一致性的要求不会太高。通常只要求数据最终一致性
CK的数据吞吐量相当大,能够存储海量的数据,并能够以水平扩展的方式进行扩容,对大表的查询计算处理效率也非常高。甚至很多场景下都可以拥有媲美于关系型数据库的查询效率。官网给出的一些测试数据也大都是上千万行*数百列的数据规模。很多大规模的数据查询也都能轻松达到毫米级别。
但是需要指出,CK高性能的背后伴随计算机资源的大量消耗,CK对内存和CPU的占用都非常高,一个很普遍的查询都可能需要消耗非常多的资源,因此CK的查询频率也不宜太高,过于频繁的连续或者并发查询甚至很容易导致服务直接崩溃
综合评价CK的特点,非常适合用于后端数仓的建设。当然,这本身也是CK的设计目标
1.3安装前的准备工作
CK官网clickhouse.com
1.3.1CentOS取消打开文件限制
/etc/security//limits.conf /etc/security/limits.d/90/nproc.cnf这两个文件末尾加入以下内容
vim /etc/security//limits.conf
*soft noflie 65536
*hard nofile 65536
*soft nproc 131072
*hard nproc 131072
vim /etc/security/limits.d/90/nproc.cnf
*soft noflie 65536
*hard nofile 65536
*soft nproc 131072
*hard nproc 131072
重启服务器之后生效 ,用ulimit -n或者ulimit -a查询设置结果
1.3.2取消SELINUX
修改/etc/selinux/config中的SELINUX=disabled(/etc/sysconfig/selinux)
vim /etc/selinux/config
SELINUX=disabled
1.3.3关闭防火墙
1.3.4安装依赖
yum install -y libtool
yum install -y *unixODBC*
安装
下载地址:https://packagecloud.io/altinity/clickhouse
https://packages.clickhouse.com/tgz/
下载安装包到本地之后执行install下的doinstall脚本
连接路径:/etc/usr
日志路径:/var/log/clickhouse
server配置文件:/etc/clickhouse-server/
client配置文件:/etc/clickhouse-client/
数据文件目录:/var/lib/clickhouse/
metadata:元数据
data:数据
使用-连接
修改配置:能远程连接
http请求 ip+8123/?query=show databases
- 使用驱动包导入官方的启动或者第三方驱动
- CK完全兼容了mysql和postgresql两个数据库,可以对应用他们的驱动直接连接,mysql服务默认端口9004,postgresql端口9005
库引擎
建库
使用数据库首先要建库,CK提供多种库引擎实现不同场景下的库声明
Atomic库引擎
这是CK默认的库引擎,默认创建的default库就是使用这种引擎,可以在监控是进行声明
create database test engine = atomic;
Atomic类型的数据库完全有CK自己管理数据。每个数据库对应/var/lib/data目录下的一个子目录。数据库中的表会分配一个唯一的UUID,数据存储的目录/var/lib.clickhouse/store/xxx/xxxxx 最后这个是该表的uuid
Mysql引擎
数据类型
CK的极简化设计在基础数据类型中体现的尤为明显
整型
CK中的整型不香其他数据库中区分int、short、long等等在这些类型,而是统一表示固定长度的整数,包括有符号整型和无符号整型。统一定义为int,后面带上数字表示占用的字节数
整型范围
- int8-[-128:127]占用8个字节,对应java中的byte
- int16-[-32768:23767]占用16个字节,对应short
- int32-[-2147483648:2147483647]占用32个字节,对应int
- int64-[-9223372036854775808:9223372036854775807]占用64个字节,对应long
无符号整型范围
- Uint8-[0:255]
- Uint16-[0:65535]
- Uint32-[0:4294967295]
- Uint64-[0:18446744073709551615]
boolean布尔类型
CK中没有定义表述true和false的布尔类型数据,通常都是直接使用Unit8
浮点型
- Float32 – float
- Float64 – double
官方建议尽量使用整型来存储数据,将固定精度的数字转换成为整数值。例如时间为毫秒为单位的保存。这是因为使用浮点型有精准度的丢失问题,例如执行select 1-0.9的出的结果将是0.09999999999999998而不是0.1。
浮点型一般用于数据值比较小,不涉及大量的统计计算,精度要求也不高的场景。例如保存商品重量,但是对于精度要求比较高的就不建议使用了
decimal型
有符号的浮点数,可以在加、减和乘法运算过程汇总保存精度。对于除法,最低有效数字将被抛弃(不会四舍五入)。通常有三种声明:Decimal32(s)、Decimal64(s)、Decimal128(s)。后面的s表示小数点后的数字位数,前面的32、64、128表示浮点精度,决定可以有多少个十进制数字(包含小数位),也就代表不同的取值范围。
数据在底层会采用与自身位宽相同的有符号整数存储。而现代CPU不支持128位的数字,因此Decimal128上的操作需要由软件来进行模拟,所以decimal的运算速度会明显比前面两个慢,也就是说尽量少用decimal128
字符串
CK的字符型数据使用String进行声明。这个字符串可以是任意长度的,包括任意字符集,包含空字节。因此,字符串类型可以代替其他数据库中的varchar、blob、clob等类型。
ck中没有编码的概念,字符串可以是任意的字节集,按他们原本的方式进行存储和输出,对于不同版本的编码文本,CK会有不同处理字符串的函数。比如length函数可以计算字符串包含的字节数组的长度,而lengthUTF8函数是假设字符串以UTF-8编码,计算的字符串包含的unicode字符的长度。
还有个固定长度的字符串类型FixdString(N),这个N就是要声明的字节数。如果字符串包含字节数不足N,将会对字符串末尾进行空字节填充。如果字符串包含的字节数大于N,将会抛出异常。可以用来保存一些例如手机号码、IP地址这一类等长的规范数据,在实际开发中使用比较少
枚举型
包含Enum8和Enum16两种类型,Enum保存’string’=integer的对应关系。在CK中,尽管用户使用的是字符串常量,但所有罕有Enum数据类型的操作都是按照包含整数来执行的,这在性能方面比使用String数据类型更有效。
Enum后面的8和16也是对应整数值integer的位宽
例如:先创建一个带枚举类型列的表。
CREATE TABLE t_enum
(
x Enum(‘hello’ = 1,’word’ = 2)
)
engine = TinyLog;
这个x列只能存储数据类型定义中列出来的值,hello或者是word,尝试inster插入其他值是会抛出异常
insert into t_enum values (‘hello’),(‘word’),(‘hello’);
SELECT *
FROM t_enum
Query id: 909b3648-e63c-4316-96fd-a003f95abd58
┌─x─────┐
│ hello │
│ word │
│ hello │
└───────┘
3 rows in set. Elapsed: 0.006 sec.
insert into t_enum values (‘hello’),(‘word’),(‘abc’);
INSERT INTO t_enum VALUES
Query id: 6ea3cfba-1bf8-4d1e-ae0e-f1854f28579f
Exception on client:
Code: 36. DB::Exception: Unknown element ‘abc’ for enum: While executing ValuesBlockInputFormat: data for INSERT was parsed from query. (BAD_ARGUMENTS)
Connecting to database test at localhost:9000 as user default.
Connected to ClickHouse server version 21.9.7 revision 54449.
select cast (x,’Int8′) from t_enum;
SELECT cast(x, ‘Int8’)
FROM t_enum
Query id: 22daf08d-c6ab-4581-916b-68e90b5a6f3c
┌─CAST(x, ‘Int8’)─┐
│ 1 │
│ 2 │
│ 1 │
└─────────────────┘
3 rows in set. Elapsed: 0.002 sec.
insert into t_enum values (1);
INSERT INTO t_enum VALUES
Query id: 9cdec16d-a370-4283-b8d9-cc9a964ad926
Ok.
1 rows in set. Elapsed: 0.003 sec.
数组类型
类型声明:array(T)。表示一个由T类型元素组成的数组,T可以是任意类型,甚至也可以是数组类型。但是不建议使用多位数组,clickhouse对多维数组的支持有限,例如在MergeTree引擎中就不能存储多维数组。
select array(1,2) AS x, toTypeName(x) ;
SELECT
[1, 2] AS x,
toTypeName(x)
Query id: e317cfe0-b9c4-4945-aa2d-bc8abc973064
┌─x─────┬─toTypeName(array(1, 2))─┐
│ [1,2] │ Array(UInt8) │
└───────┴─────────────────────────┘
1 rows in set. Elapsed: 0.002 sec.
时间类型
时间类型是每个数据库都要处理的类型。CK的时间类型声明相对简单很多。在CK中有三种时间类型
- Dtae 可以接受一个年-月-日格式的字符串。例如‘2021-10-13’
- Datetime 可以接受一个年-月-日 时:分:秒 格式的字符串
- Datetime64 可以接受一个 年-月-日 时:分:秒.毫秒 格式的字符串
可为空类型
绝大部分的基础类型都可以通过前面的添加Nullable()声明来允许接受Null空值。例如Nullable(Int8)类型的列可以存储Int8类型的值,没有值得行将存储Null
Nullable类型字段不能包含在彪索引中,并且使用Nullable几乎总是对性能产生负面影响,在设计数据库时要尽量避免使用Nullable,例如对于字符串,可以用空字符代替Null,而对于整型数据,可以用无业务意义的数字例如-1表示NUll
create table t_null ( x Int8, y Nullable(Int8)) engine TinyLog;
INSERT INTO t_null VALUES (1,NULL),(2,3);
SELECT x+y FROM t_null;
SELECT x + y
FROM t_null
Query id: 59b60442-a09f-4dce-8c69-7fec076042e9
┌─plus(x, y)─┐
│ ᴺᵁᴸᴸ │
│ 5 │
└────────────┘
2 rows in set. Elapsed: 0.002 sec.
CK中还涉及非常多有特色的数据类型,例如Geo,Map,Tuple,UUID等类型,具体参见官方文档https://clickhouse.com/docs/zh/sql-reference/data-types/