ClickHosue

文档

官网地址:Fast Open-Source OLAP DBMS - ClickHouse

文档地址:ClickHouse中文文档 | ClickHouse中文文档 (roadgulf.cn)

可视化工具:DBeaver

优点

1.灵活的MPP架构(大模型并行处理),支持现行扩展,简单方便,高可靠性;

2.多服务器分布式处理数据,完备的DBMS系统(数据库管理系统);

3.底层数据列示存储,支持压缩,优化数据存储,优化索引数据,优化底层存储;

4.支持数据统计分析,支持类SQL查询,异地复制部署,分布式运算,出色的函数支持;

缺点

  1. 不支持事物,不支持真正的删除/更新(批量);

2.不支持高并发,官方建议QPS为100,可通过修改配置文件增加连接数;

3.不支持二级索引;

4.不擅长多表join大宽表;

5.元数据管理需要人为干涉;

6.尽量做1000条以上批量的写入,避免逐行insert或小批量的insert、update、delete

应用场景

1.绝大多数请求都是用于读访问的,要求实时返回结果;

2.数据需要以大批次(大于1000)进行更新,而不是单行更新,或者没有更新操作

3.数据只是添加到数据库,没有必要修改;

  1. 读数据时,会从数据库中读取大量的行,但只用到一小部分列;

5.表很"宽",即表中包含大量的列;

6.查询频率相对较低(通常没台服务器每秒查询数百次或更少);

7.对于简单查询,允许大约50毫秒的延迟;

8.列的值是比较小的数值或字符串(例如:每个URL只有60个字节);

9.在处理单个查询时需要高吞吐量(每台服务器每秒高达数十亿行);

10.不需要事物;

11.数据一致性较低(原子性、持久性、一致性、隔离性)

12.每次查询中只会查询一个大表,除了一个大表,其余都是小表;

13.查询结果显著小于数据源,即数据有过滤或聚合,返回结果不超过单个服务器内存小;

核心概念

1)数据分片:将数据进行横向切分,每个分片对应了Clickhouse的1个服务节点,还提供了本地表(Local Table)与分布式表(Distributed Table)的概念,本地表等同于一份数据的切片,而分布式表本身不存储数据,它是本地表的访问代理,类似分库中间件,借助分布式表,能够访问多个数据切片,从而实现分布式查询。

2)列式存储:a.同一列中的数据属于同一类型,列存的压缩比更高,节省了大量存储空间;b.压缩比高意味着更小的data size,从磁盘中读数据时间更短;c.可以根据根据不同列的类型选择最合适的压缩算法;

3)向量化:Clickhouse不仅将数据按列存储,而且按列计算,将多次for循环计算变成一次计算;

4)表;

5)分区:ClickHouse支持PARTITION BY字句,在建表时可以按照表达式进行数据分区操作,比如:toYYYYMM()按月分区,toMonday()按周分区,对num类型的列分区,数据以分区的形式统一管理和维护一批数据;

6)副本:通过复制集,保障数据的可靠性,也通过多副本的方式,增加了CK查询的并发能力,a.分布式DDL执行、ReplicatedMergeTree表主备节点之间的状态同步; c.并发访问数据;d.索引的使用;e.是否可以执行多线程请求;f.数据是否存储副本;g.并发操作insert into tb_x select * from tb_x 表引擎决定数据在文件系统中的存储方式,官方推荐的存储引擎是MergeTree系列,数据副本用ReplicatedMergeTree系列,读取集群数据需要使用分布式表引擎Distribute;

7)block:ClickHouse能处理的最小单位是block,block是一群行的集合,默认最大为8192行。因为每一列单独存储,因此每个数据文件相比于行式存储更有规律,通过对block采用LZ4压缩算法,整体压缩比大致可以8:1。ClickHouse通过出色的压缩比与block结构实现了批处理功能;

8)LSM:LSM的原理:把一颗大树拆分成N棵小树,数据先写入内存中,随着小树越来越大,内存的小树会flush到磁盘中。磁盘中的树定期做合并操作,合并成一棵大树。ClickHouse通过LSM实现数据的预排序,从而减少磁盘的读取量;ClickHouse的写入步骤可以总结为以下几点:a.每一批次数据写入,先记录日志,保证高可用机制;b.记录日志之后存入内存排序,后将有序结果写入磁盘,记录合并次数Level=0; c.定期将磁盘上Level=0或1的文件合并,并标记删除,后续物理删除;

9)索引:ClickHouse的采用一级索引(稀疏索引)+二级索引(跳数索引)来实现索引数据定位与查询。一级索引记录每个block块的第一个,每次基于索引字段查询只需要确定查询第几个block块即可,避免一个查询遍历所有数据,一级索引占用存储较小,可常驻内存,加速查询。二级索引由数据的聚合信息构建而成,根据索引类型的不同,其聚合信息的内容也不同,跳数索引的目的与一级索引一样,也是帮助查询时减少数据扫描的范围,原则都是"排除法",即尽可能的排除那些一定不满足条件的索引粒度。

分布式

分布式表的特点:1.表存储多个副本且有并发操作;2表特别大有多个切片组成,并且每个切片也可以存储多个副本;3.本地表是承接数据的载体,可以使用非Distributed引擎,一个本地表对应了一个数据分片;4.分布式表只能用Distributed引擎,与本地表形成一对多的映射关系,通过分布式表代理操作多张本地表;

sql 复制代码
<!--第一步  增加配置文件-->
<remote_servers>
        <ycloud_clickhouse_cluster>      <!--集群名称-->
            <shard>                      <!--集群的第一个分片-->
                <internal_replication>true</internal_replication>
                <replica>                <!--该分片的第一个副本-->
                    <host>192.168.1.1</host>       
                    <port>9920</port>
                    <user>default</user>
                    <password>ycloud_123</password>
                </replica>
            </shard>

            <shard>                        <!--集群的第二个分片-->
                <internal_replication>true</internal_replication>
                <replica>                    <!--该分片的第一个副本-->
                    <host>192.168.1.2</host>
                    <port>9920</port>
                    <user>default</user>
                    <password>ycloud_123</password>
                </replica>
            </shard>

            <shard>                             <!--集群的第三个分片-->
                <internal_replication>true</internal_replication>
                <replica>                        <!--该分片的第一个副本-->
                    <host>192.168.1.3</host>
                    <port>9920</port>
                    <user>default</user>
                    <password>ycloud_123</password>
                </replica>
            </shard>
        </ycloud_clickhouse_cluster>
    </remote_servers>

<!--第二步 创建本地表--> 

----创建本地表
create table tb_demo on cluster 集群名(
        id Int8
        name STring
)engine=MergeTree()
order by id;

<!--第三步 创建分布式表--> 
---创建分布式表与本地表映射
create table demo_all on cluster 集群名 ENGINE=Distributed('集群名','test','tb_demo',id) as tb_demo;

ENGINE=Distributed(cluster,database,table,[,sharding_key])
cluster:集群名
database和table:数据库名和表名,分布式表使用这组配置操作本地表
sharding_key:分片键(选填参数),在数据写入过程中,分布式表会依据分片键的规则,将数据分布到各个host节点的本地表

drop table if exists 表名 on cluster 集群名;          ----删除集群中的表结构
alter table 表名 cluster 集群名 add column age Int8;   ----修改集群中的表结构(添加字段)

文件目录结构

bash 复制代码
程序在安装过程中会自动构建整套目录结构
1)/etc/clickhouse-ser  服务端配置文件目录
        config.xml   全局配置
        users.xml    用户配置
2)/var/lib/clickhouse  默认的数据存储目录(通常修改默认目录,将数据保存到大容量挂载的路径)
        data  数据存储目录(数据库和表)
        metadata   元数据信息
3)/var/log/clickhouse-server 默认保存日志目录
4)/usr/bin   默认添加进系统环境变量中   
       find ./ -name clickhouse
          clickhouse    主程序可执行文件
          clickhouse-client    一个指向clickhouse可执行文件的软连接,供客户端使用
          clickhouse-server    一个指向clickhouse可执行文件的软连接,供服务端使用
          clickhouse-compressor   内置提供的压缩工具,可用于数据的正压反解

引擎

**数据库引擎:**在建表时可以引入外部数据库,比如:MySQL引擎允许与远程MySQL服务器交互,支持INSERT和SELECT,不支持RENAME操作。PostgreSQL引擎类似,可与远程PostgreSQL服务进行读写操作。SQLite引擎用于连接SQLite数据库。实验性引擎如MaterializeMySQL和MaterializedPostgreSQL用于实现实时数据同步。

表引擎:

MergeTree系列

1)MergeTree(合并树):MergeTree表引擎主要用于海量数据分析,支持数据分区、存储有序、主键索引、稀疏索引、数据TTL(过期时间)等;问题:该表的相同主键无法去重;

2)ReplacingMergeTree(去重合并树):为了解决MergeTree相同主键无法去重的问题,clickhouse用ReplacingMergeTree做去重,问题:a.在没有彻底optimize之前,可能无法达到主键去重的效果,比如部分数据已经被去重,仍旧有主键重复b.在分布式场景下,相同primary key的数据可能被sharding到不同节点上,不同shard间可能无法去重;c.optimize是后台动作,无法预测具体执行时间点;c.手动执行optimize在海量数据场景下要消耗大量时间,无法满足业务即时查询的需求;

3)SummingMergeTree(聚合合并树):通过SummingMergeTree来支持对主键列进行预先聚合。在后台Compaction时,会将主键相同的多行进行sum求和;问题:ClickHouse只在后台Compaction时才会进行数据的预先聚合,而compaction的执行时机无法预测,所以可能存在部分数据已经被预先聚合、部分数据尚未被聚合的情况。因此,在执行聚合计算时,SQL中仍需要使用GROUP BY子句;在预先聚合时,ClickHouse会对主键列之外的其他所有列进行预聚合。如果这些列是可聚合的(比如数值类型),则直接sum;如果不可聚合(比如String类型),则随机选择一个值。通常建议SummingMergeTree与MergeTree配合使用;

4)AggregatingMergeTree(聚合合并树):也是预先聚合引擎的一种,用于提升聚合计算的性能,与SummingMergeTree的区别在于:SummingMergeTree对非主键列进行sum聚合,而AggregatingMergeTree则可以指定各种聚合函数;

5)CollapsingMergeTree(折叠合并树):该引擎要求在建表语句中指定一个标记列Sign,后台Compaction时会将主键相同、Sign相反的行进行折叠,也即删除。Sign的值分为两类:Sign=1状态行,Sign=-1取消行;

6)VersionedCollapsingMergeTree(版本折叠合并树):该引擎在建表语句中新增了一列Version,用于在乱序情况下记录状态行与取消行的对应关系,主键相同,且Version相同、Sign相反的行,在Compaction时会被删除;

Log系列

1)Log(日志):Log引擎会将每一列都存在一个文件中,对于每一次的INSERT操作,都会对应一个数据块。存储结构包含三部分:列.bin:数据文件按列单独存储;__marks.mrk:数据标记,统一保存了数据在各个.bin文件中的位置信息;sizes.json:记录了.bin和__marks.mrk大小的信息

2)StripeLog():将所有数据都存储在了一个文件中,对于每次的INSERT操作,ClickHouse会将数据块追加到表文件的末尾StripeLog引擎同样不支持ALTER UPDATE 和ALTER DELETE 操作;

3)TinyLog():该引擎适用于一次写入,多次读取的场景。对于处理小批数据的中间表可以使用该引擎;

**Memory(内存):**内存引擎,数据以未压缩的原始形式直接保存在内存中,服务器重启数据就会消失。读写操作不会相互阻塞,不支持索引;

视图

**普通试图(normal view):**不存储任何数据,只是一个子查询。当从视图读取数据时,实际是查询创建视图的子查询语句(创建视图的查询被用作from子句中的子查询);

**物化试图(materialized view):**物化视图实际存储了一份数据。用户查询的时候和表没有区别,更像是一张时刻在预计算的表。在创建物化视图的时候也需要定义存储引擎;

**实时视图(live view):**存储CREATE语句中SELECT查询的结果,并在查询结果更改时进行更新。

窗口视图(window view):

命令

bash 复制代码
sudo /etc/init.d/clickhouse-server start    --启动服务(方式一)
service clickhouse-server start    --启动服务(方式二)
clickhouse-client -u(用户名,默认值default)  -m(交互式客户端中可以执行多行函数)  -h(服务端的host名称)   -port(端口号,默认9000)  -password(密码)   -q(非交互式下的查询语句)  -d(要操作的数据库,默认default)  -f(使用指定的格式输出结果)  -t(非交互模式下打印查询执行时间)  -stacktrace(如果出现异常,打印堆栈信息)  -config-file(配置文件的名称)

/*******************导入数据**********************/
cat file.txt | clickhouse-client -q 'insert into 库名.表名 format CSV'  --将txt中的数据插入到表中(方式一)
clickhouse-client -q 'insert into 库名.表名 format CSV' < file.txt  --将txt中的数据插入到表中(方式二)
clickhouse-client --format_csv_delimiter='_' -q 'insert into 库名.表名 format CSV' < file.txt  --将txt中的数据插入到表中(方式三)  指定txt中字段之间的分隔符--format_csv_delimiter='_'

SQL语句

sql 复制代码
show databasee;      --查看数据库
create database 数据库名;     --创建数据库
use 数据名;          --进入数据库
select currentDatabase();     --查看当期使用的数据库(currentDatabase()是函数)
show tables;                 --查看表
show create table 表名;      --查看建表语句
desc 表名;                   --查看表结构
drop table 表名;             --删除表
select generateUUIDv4(),'变量名';     --生成随机字符串
select ['zss','dds','ww'] as names,toTypeName(names);   //查看数据类型(方式一)
select array(1,2,3,4) as nums ,toTypeName(names);   //查看数据类型(方式二)

--建表语句
create table 表名(
    id1 UUID       comment '随机字符串',            --随机字符串
    id2 UInt16     comment '没有标志位的int类型',                  
    nane String,              --姓名
    cdate01 Date,            --日期(格式为:2024-01-01)
    cdate02 Date32,          --日期(格式为:2024-01-01)
    cdate02 DateTime,          --秒(格式为:2024-01-01 11:12:23)
    cdate02 DateTime64,        --毫秒(格式为:2024-01-01 11:12:23.000)
    gender Fixedstring(2)    --性别
    comm Float64             --工资
    money Decimal(7,2)       --金钱(Decimal比Float64精度高)
    fs  Array(String)  comment '用户列表'      --用户列表,数组类型(存字符串)
    color Enum('RED'=1,'BLUE'=2),     --颜色(枚举类型,只能插入括号中的内容,限制值的作用)
    student Nested(           --学生 Nested类型,对数组元素进行控制
        sid UInt32,
        sname String,
        sage String 
    ),
    aa    Tuple(s String,i Int64),        --元组类型
    ip    IPv4,                           --ip类型(用于校验IP地址格式)
    mm    Map(String,UInt8)               --map类型
)ENGINE=引擎名;      --必须要指定存储引擎,引擎决定了数据存储位置、存储特点、使用方式等; 
partition by toYYYYMMDD(create_time)      --分区(按照创建时间)
primary key (id)                          --主键(不是唯一索引)
order by (id,sku_id)                      --按照字段排序(不指定主键,排序字段默认是主键)

/******************SQL语法***************************/
optimize table 表名 final;          --合并压缩
insert into 表名 values(generateUUIDv4());    --插入UUID类型的格式(方式一)
insert into 表名 select generateUUIDv4(),'变量名';    --插入UUID类型的格式(方式二 )  
insert into 表名 values('RED'),('BLUE');    --插入Enum('RED'=1,'BLUE'=2 )枚举类型(方式一)
insert into 表名 values(1),(2);    --插入Enum('RED'=1,'BLUE'=2 )枚举类型(方式二)
insert into 表名 values([1,2,3],['zhd','zdf','fddf']);   --插入Nested类型的方式
insert into 表名 values(('yy',12)),(('ss',22))      --插入Tuple类型的方式
insert into 表名 values('192.168.19.10');       --插入IP的方式
insert into 表名 values(map('ddd',123));        --插入map的方式(方式一)
insert into 表名 values({'fsd': 233});        --插入map的方式(方式二)
insert into 表名 values(array('lay','zytf'));  --插入数组(字符串)类型 
select fs.size0 from 表名;          --用sql方式 查询数组长度
select length(fs)  from 表名;       --用函数方式 查询数组长度
select fs[1] from 表名;             --用函数方式  根据下标值查数组数据(方式一)
select arrayElement[fs,1] from 表名;   --用函数方式  根据下标值查数组数据(方式二)
select arrayMap(e->upper(e),fs) 表名;  --用函数方式 将所有字符串转成大写
select aa.s,aa.i  from 表名;            --查询元组数据方式
select mm['ddd'] from 表名;             --查询map的方式  根据key取值(方式一)
select arrayElement[mm,'ddd'] from 表名;   --用函数方式  根key查map的值(方式二)
select (1.2+3) :: Int8;                --类型强制转换
with 100 as number select money + number from 表名;     --with定义变量在和表中的字段操作
with toYYYYMM(create_time) as c_t select c_t from 表名;   --with定义变量通过函数修改字段的格式
with splitByString(',',name) as str_arr select str_arr  from 表名;   --将字符串转成数组
 --array join将数组炸开(按行显示)
select 
    id,
    name   --炸开后的别名
from 表名 
array join names as name;    --names是表中的字段【Array(String)数组类型】

inner join              --内连接
left outer join         --左外连接
right outer join        --右外连接
full outer join         --全连接
cross join              --交叉连接

--内关联  all(关联精度)全关联
select *
 from 表名1 
            all join 
      表名2 on 表名1.id=表名2.id  

--内关联  any(关联精度)任意,关联上就行
select * 
 from 表名1 
           any join 
       表名2 on 表名1.id=表名2.id   --any是关联精度(任意,关联上就行)
--内关联   asof是一种模糊连接,允许在连接键之后追加定义一个模糊连接的匹配条件
select * 
 from 表名1 
           asof join 
       表名2 on (表名1.id=表名2.id) and (表名1.2 > 表名2.2)


/*********************创建试图***********************/
create view xx_view as select id,name,age from 表名;    --创建普通试图(不会落盘)
create materialized view xx_view engine = 表引擎 populate as select * from 表名;   --创建物化试图(落盘)【materialized(物化试图)、populate(数据同步) 】

/********************操作表结构************************/
alter table 表名 add colume name2 String;    --添加字段
alter table 表名 drop colume name2 String;    --删除字段
alter table 表名 modify colume age String default '';    --修改字段类型(将age修改为字符串)
alter table 表名 comment colume name2 '用户名';    --给字段添加注释
alter table 表名 drop where id =3;        --根据ID删除数据
alter table 表名 update name2='java' where id=3   --根据id修改name的值
rename table tb_test to t1;         --修改表名
rename table tb_test to t1,ttt1 to t2;         --修改多张表名
rename table  t2 to test1.t;         --移动表到另一个库中

/**********************分区操作************************/
select name,table,partition from system.parts where table ='表名';   --查看分区信息
alter table 表名 drop partition '20240203';        --删除分区
alter table t2 REPLACE PARTITION '20240302' FROM t1  --根据分区将t1表的数据复制到t2
alter table 表名 clear colume name in partition '20240203';   --根据分区清空name字段数据
alter table 表名 detach partition '20240203';    --卸载分区(底层只是移动文件)
alter table 表名 attach partition '20240203';    --装载分区(底层只是移动文件)
相关推荐
不吃饭的猪4 天前
clickhouse-20版本安装部署
数据库·mysql·clickhouse
lhyzws4 天前
CENTOS上的网络安全工具(三十五)Portainer Kafka-Clickhouse部署 Flink安装部署与编程
clickhouse·flink·kafka
一瓢西湖水6 天前
列式数据库-以clickHouse为例
数据库·clickhouse
zhglhy6 天前
ClickHouse高性能技术解析
clickhouse
恒悦sunsite10 天前
clickhouse之clickhouse-client命令简介和使用
clickhouse·client·列式数据库·客户端命令·ctyunos
言之。12 天前
Python调用DeepSeek API查询ClickHouse
windows·python·clickhouse
zhglhy13 天前
ckman将单节点ClickHouse转为集群方案
clickhouse·ckman
葡萄月令with蒲公英14 天前
使用clickhouse_connect从csv导入数据到clickhouse报错
clickhouse
韩金群16 天前
centos离线安装配置clickhouse
linux·clickhouse·centos