ClickHouse 是由号称“俄罗斯 Google”的 Yandex 开发而来,在 2016 年开源.在计算引擎里算是一个后起之秀,在数据库领域号称是最快的.
ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。
OLAP,也叫联机分析处理(Online Analytical Processing)系统,有的时候也叫DSS决策支持系统,就是我们说的数据仓库。与此相对的是OLTP(on-line transaction processing)联机事务处理系统。可以看出一个侧重事务处理。一个侧重分析处理
ID | NAME | AGE |
---|---|---|
1 | a | 10 |
2 | b | 20 |
ID | 1 | 2 |
---|---|---|
NAME | a | b |
AGE | 10 | 20 |
Row-store | 1 | a | 10 | 2 | b | 20 |
---|---|---|---|---|---|---|
Col-store | 1 | 2 | a | b | 10 | 20 |
行式存储 | 列式存储 | |
---|---|---|
优点 | 1.数据保存在一起,对某一行数据查询效率高 2. Insert/Update比较容易 | 1.以列存储每一列都可以作为索引 2.只查询某几列只需要读取某几列的数据,避免不必要的开销。3.一列数据类型的数据便于高效的压缩 |
缺点 | 1.只需要某几列数据时所有数据会被抓取 | 1.INSERT/UPDATE比较麻烦 2.选择某几列需要进行重新组装 |
是一个数据库管理系统也就是说它是一个成体系的东西,对于数据的读写、存储、查询、修改、复制、事务、效率等等方方面面都有自己的一套东西
Yandex.Metrica :目前为止,该系统在ClickHouse中有超过13万亿条记录,并且每天超过200多亿个事件被处理
今日头条:用ClickHouse来做用户行为分析,内部一共几千个ClickHouse节点,单集群最大1200节点,总数据量几十PB,日增原始数据300TB左右
腾讯:内部用ClickHouse做游戏数据分析,并且为之建立了一整套监控运维体系。
携程:内部从18年7月份开始接入试用,目前80%的业务都跑在ClickHouse上。每天数据增量十多亿,近百万次查询请求
MYSQL | Hive | ClickHouse(区分大小写) |
---|---|---|
Byte | tinyint | Int8 / UInt8 |
short | smallint | Int16 / UInt16 |
int | int | Int32 / UInt32 |
long | bigint | Int64 / UInt64 |
varchar | string | String |
timestamp | timestamp | DateTime |
float | float | Float32 |
double | double | Float64 |
Nullable:允许用特殊标记 (NULL) 表示"缺失值",可以与 TypeName
的正常值存放一起,官方介绍使用该类型总是会拖累性能,假设有业务需要null值的可以给它一个数据里不存在的比如都是正数的数据,可以定义-1为null值
FixedString(N): 不推荐使用
N
,将抛出Too large value for FixedString(N)
异常WHERE
子句,则须要手动添加空字节(\0)以匹配FixedString
的值Array(T): 还不支持多维数组
Enum8/Enum16:Enum
保存 'string'= integer
的对应关系
,
GROUP BY,
IN,
DISTINCT中Enum 的行为与相应的数字相同Domain类型:
IPv4
是与UInt32
类型保持二进制兼容的Domain类型IPv6
是与FixedString(16)
类型保持二进制兼容的Domain类型数字类型 | 0 |
---|---|
String | ‘’ |
Date | 0000-00-00 |
DateTime | 0000-00-00 00:00:00 |
表引擎(即表的类型)决定了:
- 数据的存储方式和位置,写到哪里以及从哪里读取数据
- 支持哪些查询以及如何支持。
- 并发数据访问。
- 索引的使用(如果存在)。
- 是否可以执行多线程请求。
- 数据复制参数。
具有最小功能的轻量级引擎。当您需要快速写入许多小表(最多约100万行)并在以后整体读取它们时,该类型的引擎是最有效的
TinyLog
1.数据存储在磁盘
2.写入数据时追加到文件末尾
3.不支持并发
CREATE TABLE tiny(`id` UInt(32), `name` String,`age` UInt16)ENGINE = TinyLog
适用于高负载任务的最通用和功能最强大的表引擎。这些引擎的共同特点是可以快速插入数据并进行后续的后台数据处理。 MergeTree系列引擎支持数据复制(使用Replicated* 的引擎版本),分区和一些其他引擎不支持的其他功能。
MergeTree
1.支持分区,不支持类似hive的多级目录的分区,一般都以年月日做为分区
2.存储的数据分区内按照主键和排序字段排序,类似于mysql的联合索引(稀疏索引),需要根据业务考虑字段的先后顺序
3.稀疏索引: 对分区中排序好的数据每一段数据(默认8192)存储一个索引,这样索引占用空间就少 (类似于只有一级索引的跳表,可以实现二分查找)
3.支持数据副本
ENGINE = MergeTree()
[PARTITION BY expr] // 分区
[ORDER BY expr] // 表的排序键
[PRIMARY KEY expr] // 主键,默认和排序键相同,一般不需要设置
[SETTINGS name=value, ...] // 设置索引粒度和一些其他的配置
CREATE TABLE click.mt (`id` UInt16, `name` String, `age` UInt16, `birthDay` DateTime) ENGINE = MergeTree() PARTITION BY toYYYYMM(birthDay) ORDER BY (name, age) SETTINGS index_granularity = 8192
ReplacingMergeTree
1.该引擎和MergeTree的不同之处在于它会删除具有相同主键的重复项
2.去重合并会在后台运行,不保证没有重复数据出现
3.主键相同数据合并时如果ver列未指定会取最后一条,指定时取最大版本的(ver 类型为 UInt*, Date 或 DateTime)
CREATE TABLE click.rmt (`gmt` Date, `id` UInt16, `name` String, `point` UInt16) ENGINE = ReplacingMergeTree(point) PARTITION BY gmt ORDER BY name SETTINGS index_granularity = 8192
insert into t (gmt, id, name, point) values ('2017-07-11', 1, 'a', 20);
insert into t (gmt, id, name, point) values ('2017-07-11', 1, 'a', 30);
insert into t (gmt, id, name, point) values ('2017-07-11', 1, 'a', 10);
SummingMergeTree
1.具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值
2.主键相同合并时其他列会取第一个出现的
3.ck按片段合并,可能不会完整的汇总所有行
create table sumt(time Date, name String, a UInt16, b UInt16, c String)ENGINE=SummingMergeTree((a,b))
PARTITION BY time
ORDER BY (time,name);
insert into sumt values ('2019-07-10','a',1,2,'x'),
('2019-07-10','a',2,1,'x1'),
('2019-07-11','b',3,8,'x2'),
('2019-07-11','b',3,8,'x3'),
('2019-07-11','a',3,1,'x4'),
('2019-07-12','c',1,3,'x5');
AggregatingMergeTree
1.会将相同主键的所有行(在一个数据片段内)替换为单个存储一系列聚合函数状态的行。
2.不能直接插入数据,可以通过INSERT SELECT 或者创建物化视图
// 创建普通表
CREATE TABLE basic(StartDate Date,CounterID UInt16,Sign UInt16,UserID UInt16)ENGINE=MergeTree
PARTITION BY StartDate
ORDER BY (CounterID,StartDate);
INSERT INTO basic values('2019-09-10',1,2,1),('2019-09-10',1,3,2),('2019-10-10',2,2,4),('2019-10-10',2,4,8),('2019-09-10',3,4,9);
// 创建物化视图
CREATE MATERIALIZED VIEW basic_view
ENGINE=AggregatingMergeTree() PARTITION BY toYYYYMM(StartDate) ORDER BY (CounterID, StartDate)
AS SELECT
CounterID,StartDate,sumState(Sign) AS vists,uniqState(UserID) AS Users
FROM basic
GROUP BY CounterID,StartDate;
用于与其他的数据存储与处理系统集成的引擎。 该类型的引擎
MySQL: 会将mysql表映射过来但是不会存数据相当于一个代理,查询的时候ck会去连接mysql获取数据然后返回
CREATE TABLE mysql(id UInt16,username String,password String,gender String,createAt DateTime)
ENGINE=MySQL('127.0.0.1:3306','test','user','root','cloudera');
MaterializedMySQL: 通过binglog日志将数据都同步到ck中,没有mysql引擎的网络IO传输并且使用ck的表引擎进行计算性能比MySQL引擎高
CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster]
ENGINE = MaterializeMySQL('127.0.0.1:3306','test','user','root')
JDBC
CREATE TABLE jdbc_table(id UInt16,username String,password String,gender String,createAt DateTime)ENGINE=JDBC('jdbc:mysql://localhost:3306/?user=root&password=cloudera','test','user');
Kafka: 流式读取kafka的数据,官方建议同时建一个字段相同MergeTree引擎然后使用物化试图将kafka引擎的数据插入MergeTree中. 早期使用19版本性能很低后面官方进行持续的修复和优化建议使用的时候进行完整的测试
CREATE TABLE queue (timestamp UInt64,level String,message String)
ENGINE = Kafka('localhost:9092', 'topic', 'group1', 'JSONEachRow');
HDFS: 集成hdfs数据,类似于hive以hdfs做为存储
CREATE TABLE hdfs(id String,name String,age UInt16,star String)ENGINE=HDFS('hdfs://127.0.0.1:8020/test/person/*','CSV');
用于特定功能的引擎
Memory: 一般用于测试或一些特殊业务
1.数据存储在内存中,服务器宕机数据消失
2.支持并行
3.性能非常高
create table t1(a String, b UInt16) ENGINE=Memory;
Merge: 21版本实际使用中有性能问题,建议需要使用的时候进行完整测试
1.用于将多个表链接在一起并且可以利用原表的索引
1.本身不存储如何数据
2.不支持写操作
CREATE TABLE click.m (`id` UInt16, `name` String) ENGINE = Merge(currentDatabase(), '^m')
URL引擎:直接解析接口数据,对于一些以前使用定时任务获取别的系统的数据是可以考虑使用,该引擎就是直接去访问接口然后解析成表进行查询后返回
CREATE TABLE url_engine_table (word String, value UInt64)
ENGINE=URL('http://127.0.0.1:12345/', CSV)
Distributed: 分布式引擎本身不存数据,可以理解为mysql的分表,将数据负载均衡的写到各个服务器的本地表上,
然后通过该分布式表进行查询,ck会帮你做数据合并的操作
1.在多个服务器上进行分布式查询并且可以利用原表的索引
2.本身不存储数据
3.支持逻辑表写入,异步写入,官方推荐自己路由将数据写到各个节点的本地表上
create table d(id UInt16, name String) ENGINE=TinyLog;
insert into d(id, name) values (0, 'aaa');
insert into d(id, name) values (1, 'bbb');
create table distribute(id UInt16, name String) ENGINE=Distributed(test_unavailable_shard, click, d, id);
SELECT [DISTINCT] expr_list
[FROM [db.]table | (subquery) | table_function] [FINAL]
[SAMPLE ]
[ARRAY JOIN ...]
[GLOBAL] ANY|ALL INNER|LEFT JOIN (subquery)|table USING columns_list
[PREWHERE expr]
[WHERE expr]
[GROUP BY expr_list] [WITH TOTALS]
[HAVING expr]
[ORDER BY expr_list]
[LIMIT n BY columns]
[LIMIT [n,m]
[UNION ALL ...]
[INTO OUTFILE filename]
[FORMAT format]
ANY / ALL
GLOBAL
Group by
// 导入
cat xxx.csv | clickhouse-client --query="INSERT INTO b6logs FORMAT CSV";
// 指定分隔符
cat xxx.csv | clickhouse-client --format_csv_delimiter="|" --query="INSERT INTO b6logs FORMAT CSV";
// 导出
clickhouse-client --query="select * from user format CSV" > 9c9dc608-269b-4f02-b122-ef5dffb2669d.log
ClickHouse作为一个分析类型(OLAP)的数据库系统,相对于MySQL数据库在用户管理方面有很大不同,它是通过修改配置文件来实现用户权限管理的。在安装好ClickHouse之后,其配置文件在/etc/clickhouse-server目录下,容器中也在此目录下,对应的配置文件为users.xml,ClickHouse使用它来定义用户相关的配置项。修改了user.xml的参数之后是即时生效的
<users>
<user_name> --配置的用户
<password>password> --明文密码
<password_sha256_hex>password_sha256_hex> --加密密码,二选一
<networks incl="networks" replace="replace"> --允许登录的地址,用于限制用户登录的客户端地址
networks>
<profile>profile_nameprofile> --指定用户的profile
<quota>defaultquota> -- 指定用户的quota,限制用户使用资源
<databases> --指定数据库
<database_name>
<table_name> --指定数据表
<filter>expressionfilter>
table_name>
database_name>
databases>
user_name>
users>
密码设置
:明文密码
linux下直接生成
PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
返回值
zRB1j7H8 -- 密码
32dbe275bb31cd65f55ebca5fb50bf4ce2e7ae2fc062dacbf73f19f54362ea14 -- 加密密码
:限制用户登录的客户端地址可以通过IP,主机等进行限制
<ip>:IP地址,如10.0.0.1
<host>:主机名,如example01.host.ru
<host_regexp>:^example\d\d-\d\d-\d\.host\.ru$
来自任何IP:
<ip>::/0ip>
来自本机:
<ip>::1ip>
<ip>127.0.0.1ip>
:指定用户的profile
:指定用户访问的过滤器,限制返回符合条件的行。如:id > 1 ,即查询表只返回id>1的行
查询权限管理
1.读权限:SELECT, SHOW, DESCRIBE, EXISTS
2.写权限:INSERT, OPTIMIZE.
3.设置权限:SET, USE
4.DDL权限:CREATE, ALTER, RENAME, ATTACH, DETACH, DROP TRUNCATE
5.kill QUERY 权限
控制标签
<profiles> --标签在profiles里设置
<normal> --只读,不能DDL
<readonly>1readonly>
<allow_ddl>0allow_ddl>
normal>
<normal_2> --只读,即使DDL允许
<readonly>1readonly>
<allow_ddl>1allow_ddl>
normal_2>
<normal_3> --读写,能DDL
<readonly>0readonly>
<allow_ddl>1allow_ddl>
normal_3>
profiles>
<users>
<test>
<password>123456password>
<networks incl="networks" replace="replace">
<ip>::/0ip>
networks>
<profile>normal_3profile> --用户引用相关profile
<quota>defaultquota>
test>
users>
<yandex>
<profiles>
<default>
<max_memory_usage>100000000max_memory_usage>
<use_uncompressed_cache>0use_uncompressed_cache>
<load_balancing>randomload_balancing>
default>
<readonly>
<readonly>1readonly>
readonly>
<readwrite>
<constraints>
<max_memory_usage>
<readonly/>
max_memory_usage>
<force_index_by_date>
<readonly/>
force_index_by_date>
constraints>
readwrite>
profiles>
<users>
<default> -- 因为profiles里默认的profile是没有限制的,所以default就是默认管理员账号
<password>password>
<networks incl="networks" replace="replace">
<ip>::/0ip>
networks>
<profile>defaultprofile>
<quota>defaultquota>
default>
<zhoujy_ro>
<password_double_sha1_hex>6bb4837eb74329105ee4568dda7dc67ed2ca2ad9password_double_sha1_hex>
<networks incl="networks" replace="replace">
<ip>::/0ip>
networks>
<profile>readonlyprofile>
<quota>defaultquota>
zhoujy_ro>
<zhoujy_rw>
<password_double_sha1_hex>6bb4837eb74329105ee4568dda7dc67ed2ca2ad9password_double_sha1_hex>
<networks incl="networks" replace="replace">
<ip>192.168.163.132ip>
networks>
<profile>readwriteprofile>
<quota>defaultquota>
zhoujy_rw>
<zhoujy_admin>
<password_double_sha1_hex>6bb4837eb74329105ee4568dda7dc67ed2ca2ad9password_double_sha1_hex>
<networks incl="networks" replace="replace">
<ip>192.168.163.132ip>
<ip>192.168.163.133ip>
networks>
<profile>defaultprofile>
<quota>defaultquota>
zhoujy_admin>
<zhoujy_db>
<password_double_sha1_hex>6bb4837eb74329105ee4568dda7dc67ed2ca2ad9password_double_sha1_hex>
<networks incl="networks" replace="replace">
<ip>::/0ip>
<ip>127.0.0.1ip>
<ip>192.168.163.132ip>
networks>
<profile>readwriteprofile>
<quota>defaultquota>
<allow_databases>
<database>testdatabase>
allow_databases>
zhoujy_db>
<zhoujy_tb>
<password_double_sha1_hex>6bb4837eb74329105ee4568dda7dc67ed2ca2ad9password_double_sha1_hex>
<networks incl="networks" replace="replace">
<ip>::/0ip>
<ip>127.0.0.1ip>
<ip>192.168.163.132ip>
networks>
<profile>readonlyprofile>
<quota>defaultquota>
<allow_databases>
<database>testdatabase>
allow_databases>
<databases>
<IT>
<table1>
<filter>id >= 500 filter>
table1>
IT>
databases>
zhoujy_tb>
users>
yandex>