【CK】ClickHouse入门

news/2024/10/18 7:55:10/

简介

ClickHouse是"战斗民族"俄罗斯搜索巨头Yandex公司开源的一个极具"战斗力"的实时数据分析数据库,是面向 OLAP 的分布式列式DBMS,圈内人戏称为"喀秋莎数据库"。ClickHouse简称"CH",但在中文社区里大家更偏爱"CK",反馈是因为有"AK"的感觉!与Hadoop、Spark这些巨无霸组件相比,ClickHouse很轻量级,且不依赖于其他组件

  1. 下载仓库:https://repo.yandex.ru/clickhouse
  2. 中文文档:https://clickhouse.yandex/docs/zh/

通过实践应用,ClickHouse完美解决了MySQL的查询瓶颈,20亿行以下的数据量级查询,90%都可以在亚秒(1秒内)给到结果,并深受腾讯、快手、今日头条、携程等一线大厂的青睐。ClickHouse特点鲜明: ROLAP、在线实时查询、完整的DBMS、列式存储、不需要任何数据预处理、支持批量更新、具有非常完善的SQL支持和函数、支持高可用、不依赖Hadoop复杂生态、开箱即用……当然,还有最重要的一点就是查询速度变态快!1亿数据: ClickHouse比Vertica快5倍,比Hive快279倍,比MySQL快801倍!

适用场景

适用场景从社区分享的案例看主要有以下几类:日志数据的行为分析,标签画像的分析,数据集市层分析;还可作为存储引擎集成在了产品内部,应用于知识图谱作为本体数据存储,及标签数据的存储引擎等。
一般使用方式场景建议:
 绝大多数请求都是用于读访问
 表很"宽",即表中包含大量的列
 在处理单个查询时需要高吞吐量
 每次查询中大多数场景查询一个大表
 查询结果显著小于数据源,即数据有过滤或聚合

性能测试对比

性能测试对比如下图:

Clickhouse优缺点及性能情况

优点:

1,为了高效的使用CPU,数据不仅仅按列存储,同时还按向量进行处理;

2,数据压缩空间大,减少IO;处理单查询高吞吐量每台服务器每秒最多数十亿行;

3,索引非B树结构,不需要满足最左原则;只要过滤条件在索引列中包含即可;即使在使用的数据不在索引中,由于各种并行处理机制ClickHouse全表扫描的速度也很快;

4,写入速度非常快,50-200M/s,对于大量的数据更新非常适用。

缺点:

1,不支持事务,不支持真正的删除/更新;

2,不支持高并发,官方建议qps为100,可以通过修改配置文件增加连接数,但是在服务器足够好的情况下;

3,SQL满足日常使用80%以上的语法,join写法比较特殊;最新版已支持类似SQL的join,但性能不好;

4,尽量做1000条以上批量的写入,避免逐行insert或小批量的insert,update,delete操作,因为ClickHouse底层会不断的做异步的数据合并,会影响查询性能,这个在做实时数据写入的时候要尽量避开;

5,Clickhouse快是因为采用了并行处理机制,即使一个查询,也会用服务器一半的CPU去执行,所以ClickHouse不能支持高并发的使用场景,默认单查询使用CPU核数为服务器核数的一半,安装时会自动识别服务器核数,可以通过配置文件修改该参数。

数据迁移:从 MySQL 到 ClickHouse

ClickHouse 支持 MySQL 大多数语法,迁移成本低,数据迁移需要从 mysql 导入 clickhouse, 总结方案如下,clickhouse 自身支持的三种方式。

create table engin 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 数据库中,可以理解成外表。可以通过在 mysql 增删数据进行验证。

insert into select from

-- 先建表
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
-- 导入数据
INSERT INTO [db.]table [(c1, c2, c3)] select 列或者* from mysql('host:port', 'db', 'table_name', 'user', 'password')

可以自定义列类型,列数,使用 clickhouse 函数对数据进行处理

create table as select from

CREATE TABLE IF NOT EXISTS `article_clientuser_sum` ENGINE =Log AS
SELECT * FROM mysql('host:port', 'db', 'article_clientuser_sum', 'user', 'password')CREATE TABLE IF NOT EXISTS `article_clientuser_sum` ENGINE =MergeTree() PARTITION BY toYYYYMMDD(rectime) ORDER BY id AS 
SELECT * FROM mysql('host:port', 'db', 'article_clientuser_sum', 'user', 'password')

可以理解成 create table 和 insert into select 的组合。PARTITION BY分区键,不声明分区键,则会默认生成一个名为all的分区 

建表语句

Clickhouse 中最强大的表引擎当属MergeTree(合并树)引擎及该系列(*MergeTree)中的其他引擎。MergeTree引擎系列的基本理念如下。当你有巨量数据要插入到表中,你要高效地一批批写入数据片段,并希望这些数据片段在后台按照一定规则合并。相比在插入时不断修改(重写)数据进存储,这种策略会高效很多。Mergetree在写入数据时,数据总会以数据片段的形式写入磁盘,为了避免片段过多,ClickHouse会通过后台线程,定期合并这些数据片段,属于相同分区的数据片段会被合并成一个新的片段,正式合并树名称的由来。

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],...INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

主要参数:

PARTITION BY

分区键,不声明分区键,则会默认生成一个名为all的分区。

ORDER BY

必填,排序键,默认情况下主键与排序键相同。

PRIMARY KEY

会根据主键字段生成一级索引,用于加速查询,可不声明,默认是ORDER BY定义的字段。

SAMPLE BY

抽样表达式,声明数据以何种标准进行采样,如果使用此配置,必须子主键的配置中也声明同样的表达式。
ORDER BY (CounterID,intHash32(UserID))
SAMPLE BY intHash32(UserID)

SETTINGS

index_granularity:索引粒度,默认8192,也就每隔8192行才生成一条索引
enable_mixed_granularity_parts:是否开启自适应索引间隔功能,默认开启
index_granularity_bytes:索引粒度,根据每一批次写入数据的大小,动态划分间隔大小,默认10M(10*1024*1024)

CREATE TABLE user
(`id`          UInt64, --UInt8,UInt16,UInt32,UInt64,Int8,Int16,Int32,Int64`name`        String,`password`    String,`telephone`   String,`create_time` DateTime DEFAULT now(),`create_day`  Date     DEFAULT CAST(now(), 'Date')
) ENGINE = MergeTree(create_day, intHash32(id), 8192)

布尔值:没有单独的类型来存储布尔值。可以使用 UInt8 类型,取值限制为 0 或 1。
固定字符串:固定长度 N 的字符串(N 必须是严格的正自然数)。SHA256使用FixedString(32)

CREATE TABLE test.part
(`ID` String,`URL` String,`age` UInt8 DEFAULT 0,`EventTime` Date
)
ENGINE = MergeTree()PARTITION BY toYYYYMMDD(EventTime)ORDER BY IDSETTINGS index_granularity = 8192

存储结构

查看目录结构

[root@test 20200801_12_12_0]# ll
总用量 56
-rw-r----- 1 clickhouse clickhouse  29 8月  18 15:56 age.bin
-rw-r----- 1 clickhouse clickhouse  48 8月  18 15:56 age.mrk2
-rw-r----- 1 clickhouse clickhouse 456 8月  18 15:56 checksums.txt
-rw-r----- 1 clickhouse clickhouse  91 8月  18 15:56 columns.txt
-rw-r----- 1 clickhouse clickhouse   1 8月  18 15:56 count.txt
-rw-r----- 1 clickhouse clickhouse  32 8月  18 15:56 EventTime.bin
-rw-r----- 1 clickhouse clickhouse  48 8月  18 15:56 EventTime.mrk2
-rw-r----- 1 clickhouse clickhouse  42 8月  18 15:56 ID.bin
-rw-r----- 1 clickhouse clickhouse  48 8月  18 15:56 ID.mrk2
-rw-r----- 1 clickhouse clickhouse   4 8月  18 15:56 minmax_EventTime.idx
-rw-r----- 1 clickhouse clickhouse   4 8月  18 15:56 partition.dat
-rw-r----- 1 clickhouse clickhouse  10 8月  18 15:56 primary.idx
-rw-r----- 1 clickhouse clickhouse  49 8月  18 15:56 URL.bin
-rw-r----- 1 clickhouse clickhouse  48 8月  18 15:56 URL.mrk2
[root@test 20200801_12_12_0]# pwd
/var/lib/clickhouse/data/test/part_v1/20200801_12_12_0

目录层次:数据库名 > 数据表名 > 分区目录 > 分区下具体文件
20200801_12_12_0是分区名

.txt是明文存储,.bin/.dex/.mrk二进制存储

  • partition.dat: 分区信息
  • checksum.txt: 数据校验信息
  • columns.txt: 列信息
  • count.txt: 计数信息
  • primary.idx: 一级索引信息,用于存储稀疏索引信息
  • [column].bin: 存储某一列的信息,默认使用lz4压缩算法存储
  • [column].mrk: 列字段标记问题,保存.bin文件中数据的偏移量信息
  • [column].mrk2: 如果定义了自适应索引,则会出现该文件,作用和.mrk文件一样
  • partition.dat、minmax_[column].idx: 定义了分区键,会出现这二个文件,partition存储当前分区下分区表达式最终生成的值,minmax_[column].idx记录当前分区下对应原始数据的最小最大值
  • skp_idx_[Column].idx与skp_idx_[Column].mrk: 二级索引信息

数据分区

数据的分区规则

分区规则由分区ID决定,,分区ID生成规则有四种逻辑

  • 不指定分区键:没有定义PARTITION BY,分区ID默认all
  • 使用整型:直接按该整型的字符串形式输出,做为分区ID
  • 使用日期类型:分区键时日期类型,或者可以转化成日期类型,比如用today转化,YYYYMMDD格式按天分区,YYYYMM按月分区等
  • 使用其他类型:String、Float类型等,通过128位的Hash算法取其Hash值作为分区ID

数据进行分区存储,在查询时可以快速定位数据位置

分区目录的命名规则

分区命名规则,对于20200801_1_1_0
PartitionID_MinBlockNum_MaxBlockNum_Level

  • PartitionID: 分区ID,20200801就是分区ID
  • MinBlockNum、MaxBlockNum: 最小分区块编号和最大分区块编号,BlockNum是整型的自增长编号,从1开始,新创建一个分区目录时,会+1,新创建的分区MinBlockNum=MaxBlockNum
  • Level:合并的层级,被合并的次数

分区目录的合并过程

每次数据insert写入,都会生成新的分区目录,在之后的某个时刻(写入后的10-15分钟,也可以手动执行optimize强制合并)会通过后台任务再将属于相同分区的多个目录合并成一个新的目录,已经存在的目录通过后台任务删除(默认8分钟)。

合并之后新目录名规则:

  • MinBlockNum:取同一分区内所有目录中最小的MinBlockNum值
  • MaxBlockNum:取同一分区内所有目录中最大的MaxBlockNum值
  • Level:取同以分区内最大Level值并+1

一级索引

一级索引也就是主键索引,通过PRIMARY KEY/ORDER BY定义
会写入primary.idx文件中

稀疏索引和稠密索引的区别

稀疏索引使用一个索引标记一大段时间,减少了索引的数据量,使得primary.idx可以常驻内存,加速数据查询

数据索引的生成过程

PARTITION BYtoYYYYMM(EventDate)),所以2014年3月份的数据最终会被划分到同一个分区目录内。使用CounterID作为主键(ORDER BY CounterID),每间隔8192行会生成一个主键索引保存到primary.idx文件中

压缩数据块

数据标记的生成规则

数据标记是衔接一级索引和数据的桥梁

数据标记和索引区间是对齐的,均按照index_granularity的粒度间隔。只需简单通过索引区间的下标编号就可以直接找到对应的数据标记。每一个列字段[Column].bin文件都有一个与之对应的[Column].mrk数据标记文件,用于记录数据在.bin文件中的偏移量信息

一行标记数据使用一个元组表示,元组内包含两个整型数值的偏移量信息。对应的.bin压缩文件中,压缩数据块的起始偏移量;以及将该数据压缩块解压后,其未压缩数据的起始偏移量
每一行标记数据都表示了一个片段的数据(默认8192行)在.bin压缩文件中的读取位置信息。标记数据与一级索引数据不同,它并不能常驻内存,而是使用LRU(最近最少使用)缓存策略加快其取用速度。

分区、索引、标记和压缩数据的协同总结

写入过程

首先生成分区目录,属于相同分区的目录会依照规则合并到一起
紧接着按照index_granularity索引粒度,会分别生成primary.idx一级索引(如果声明了二级索引,还会创建二级索引文件)、每一个列字段的.mrk数据标记和.bin压缩数据文件

查询过程

查询的本质,可以看作一个不断减小数据范围的过程。在最理想的情况下,MergeTree首先可以依次借助分区索引、一级索引和二级索引,将数据扫描范围缩至最小。然后再借助数据标记,将需要解压与计算的数据范围缩至最小

如果一条查询语句用不到索引会进行分区目标扫描,虽不能缩小数据范围,但是MergeTree仍然能够借助数据标记,以多线程的形式同时读取多个压缩数据块,以提升性能

数据标记和压缩数据块的对应关系

每个压缩数据块的体积都被严格控制在64KB~1MB。而一个间隔(index_granularity)的数据,又只会产生一行数据标记,根据一个间隔内数据的实际字节大小,数据标记和压缩数据块之间会产生三种不同的对应关系

多对一

多个数据标记对应一个压缩数据块,当一个间隔(index_granularity)内的数据未压缩大小size小于64KB时,会出现这种对应关系。

一对一

一个数据标记对应一个压缩数据块,当一个间隔(index_granularity)内的数据未压缩大小size大于64KB小于1M时,会出现这种对应关系。

一对多

一个数据标记对应多个压缩数据块,当一个间隔(index_granularity)内的数据未压缩大小size大于1M时,会出现这种对应关系。

二级索引

二级索引又称跳数索引,由数据的聚合信息构建而成,根据索引类型的不同,其聚合信息的内容也不同。
需要在CREATE语句内定义,定义了跳数索引会额外生成相应的索引文件后标记文件
skp_idx_[Column].idx和skp_idx_[Column].mrk

批量写入

INSERT INTO user (id,name,password,telephone) VALUES (1,'张三','123','15466668888'),(2,'李四','234','15366668888'),(3,'王五','345','15266668888');

Json数据插入

INSERT INTO database.table_name FORMAT JSONEachRow{"id":"1", "name":"test", "age":"11", "flag":"1"}

Ubuntu/Debian安装

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E0C56BD4    # optional
sudo apt-add-repository "deb http://repo.yandex.ru/clickhouse/deb/stable/ main/"
sudo apt-get update
sudo apt-get install clickhouse-server-common clickhouse-client -y
sudo service clickhouse-server start
clickhouse-client#用户密码访问
clickhouse-client -u default --passwordtail -f /var/log/clickhouse-server/clickhouse-server.log

使用/etc/clickhouse-server/config.xml作为配置文件,也可以手动启动,指定配置文件:

DB::NetException: Connection refused (localhost:9000, ::1

使用clickhouse-client命令默认连接的是9000端口,所以在连接的时候需要指定端口(或者修改tcp_port),clickhouse-client --port 80

开启远程访问/etc/clickhouse-server/config.xml去掉注释

<listen_host>::</listen_host>

DB::Exception: Effective user of the process (root) does not match the owner of the data (clickhouse). Run under 'sudo -u clickhouse'

sudo -u clickhouse clickhouse-server --config-file=/etc/clickhouse-server/config.xml

进入到clickhouse客户端,与MySQL客户端类似,show databases、show tables等,简单试下

localhost :) show databasesSHOW DATABASES┌─name────┐
│ default │
│ system  │
└─────────┘2 rows in set. Elapsed: 0.030 sec.

JAVA其实 Mybatis 还可以操作 ClickHouse,这里用 Druid 进行连接管理

<dependency><groupId>ru.yandex.clickhouse</groupId><artifactId>clickhouse-jdbc</artifactId><version>0.1.40</version>
</dependency>

注意事项:clickhouse的http访问默认端口是8123,tcp默认端口是9000。所有jdbc连接ck的端口是8123。9009端口,用于集群复制数据。用户名默认default,密码为空,可以在/etc/clickhouse-server/users.xml修改

root@PC-202003221735:/# echo -n "0rb!t" | sha256sum | tr -d '-'
echo -n "0rbtail -f /data/www/html/a.txt " | sha256sum | tr -d '-'
817729d06941a2fb974367c82e52f77ecc8b8284add6f103ca756aa096ead8e6<!--
<password>0rb!t</password>
-->
<password_sha256_hex>817729d06941a2fb974367c82e52f77ecc8b8284add6f103ca756aa096ead8e6</password_sha256_hex>

php 

composer require smi2/phpclickhouse

aaa 


http://www.ppmy.cn/news/802420.html

相关文章

CKPlayer

http://www.ckplayer.com/ 原文&#xff1a;http://www.cnblogs.com/Athrun/p/ckplayer.html <div id"flashcontent"></div><div id"video" style"position:relative;z-index: 100;width:600px;height:400px;"><div id&q…

CYK算法详解

在计算机科学领域&#xff0c;CYK算法&#xff08;也称为Cocke–Younger–Kasami算法&#xff09;是一种用来对 上下文无关文法&#xff08;CFG&#xff0c;Context Free Grammar&#xff09;进行语法分析&#xff08;parsing&#xff09;的算法。该算法最早由John Cocke, Dani…

自然语言处理(NLP)-统计句法分析(CKY算法用于PCFG下的句法分析)

1.先解释何为CFG及PCFG&#xff1a; 一个栗子&#xff1a; 2.CKY算法&#xff08;或称CYK算法&#xff09; “在计算机科学领域&#xff0c;CYK算法&#xff08;也称为Cocke–Younger–Kasami算法&#xff09;是一种用来对 上下文无关文法&#xff08;CFG&#xff0c;Context F…

LeetCode-每日一题【2095.删除链表的中间节点】

题目 给你一个链表的头节点 head 。删除 链表的 中间节点 &#xff0c;并返回修改后的链表的头节点 head 。 长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点&#xff08;下标从 0 开始&#xff09;&#xff0c;其中 ⌊x⌋ 表示小于或等于 x 的最大整数。 对于 n 1、…

从Vue快速上手React

前言 还没使用过React 的 vue同学可以通过这篇博客快速上手React。 1、数据读写 Vue 数据读写&#xff1a; import { ref, reactive } from vueconst str ref<string>(Aos) const obj reactive<Record<string, string>>({name: vue,version: 3.2.x }) …

汉字拼音首字母

http://hi.baidu.com/stavevai/blog/item/9c76bea574baabff9052ee84.html 为方便拼音用户输入一些汉字&#xff0c;有时候我们需要提供一些拼音首字母的输入方法&#xff0c;这时候需要把相关的汉字的首字母提取出来。 下面这个例子用空间换时间&#xff0c;用查表的方法实现了…

Pinyin4j 汉字转拼音使用教程

目录 Pinyin4j 概述与下载 Pinyin4j 使用快速入门 Pinyin4j 概述与下载 1、pinyin4j 是一个开源的流行 java 库&#xff0c;用来处理中文转换成拼音&#xff0c;拼音输出格式可定制。 官网&#xff1a;http://pinyin4j.sourceforge.net 在线文档&#xff1a;http://pinyin4j…

如何用搜狗拼音输入法输入希腊字母

https://jingyan.baidu.com/article/48b37f8d09d18c1a6464882c.html 方法一&#xff1a;软键盘 右击输入法悬浮窗打开菜单-选择软键盘 这里有很多软键盘&#xff0c;其中第二个就是希腊字母软键盘&#xff0c;点击打开 第二次使用可以点击输入法悬浮窗上的软键盘快捷键来快速…