ClickHouse 是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。
在传统的行式数据库系统中,数据按如下顺序存储:
处于同一行中的数据总是被物理的存储在一起。常见的行式数据库系统有:MySQL、Postgres等。
在列式数据库系统中,数据按如下的顺序存储:
这些示例只显示了数据的排列顺序。来自不同列的值被单独存储,来自同一列的数据被存储在一起。
不同的数据存储方式适用不同的业务场景,数据访问的场景包括:进行了何种查询、多久查询一次以及各类查询的比例;每种类型的查询(行、列和字节)读取多少数据;读取数据和更新之间的关系;使用的数据集大小以及如何使用本地的数据集;是否使用事务,以及它们是如何进行隔离的;数据的复制机制与数据的完整性要求;每种类型的查询要求的延迟与吞吐量等等。
(摘抄自 ClickHouse 官网)
在一个真正的列式数据库管理系统中,除了数据本身外不应该存在其他额外的数据。这意味着为了避免在值旁边存储它们的长度«number»,你必须支持固定长度数值类型。例如,10 亿个 UInt8 类型的数据在未压缩的情况下大约消耗 1GB 左右的空间,如果不是这样的话,这将对 CPU 的使用产生强烈影响。即使是在未压缩的情况下,紧凑的存储数据也是非常重要的,因为解压缩的速度主要取决于未压缩数据的大小。
这是非常值得注意的,因为在一些其他系统中也可以将不同的列分别进行存储,但由于对其他场景进行的优化,使其无法有效的处理分析查询。例如: HBase,BigTable,Cassandra,HyperTable。在这些系统中,你可以得到每秒数十万的吞吐能力,但是无法得到每秒几亿行的吞吐能力。
需要说明的是,ClickHouse 不单单是一个数据库, 它是一个数据库管理系统。因为它允许在运行时创建表和数据库、加载数据和运行查询,而无需重新配置或重启服务。
(摘抄自 ClickHouse 官网)
这里介绍 ClickHouse 离线安装时必要的四个安装包:
clickhouse-common-static
:安装 ClickHouse 编译的二进制文件。clickhouse-server
:为默认服务器配置创建符号链接 clickhouse-server
并安装。clickhouse-clientclickhouse-client
:为其他客户端相关工具创建符号链接。并安装客户端配置文件。clickhouse-common-static-dbg
:安装带有调试信息的 ClickHouse 编译二进制文件。安装包官网下载地址:
注意,这四个文件必须选择同一个版本!
我的安装环境:
21.9.4.35
# 防火墙状态查看
systemctl status firewalld.service
# 临时关闭
systemctl stop firewalld.service
# 永久关闭防火墙
systemctl disable firewalld.service。
vim /etc/security/limits.conf
在文件中添加如下内容:
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072
vim /etc/security/limits.d/20-nproc.conf
在文件中添加如下内容:
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072
vim /etc/selinux/config
将 SELINUX 状态修改为 disabled
。
该配置文件需要重启后才会生效,我们可以使用命令 setenforce 0
来进行临时关闭。
yum install -y libtool
如果你是 .tgz
格式的压缩包,请参考这篇博客 ClickHouse 单机安装与一些安装时可能出现的问题解决方法
我这里已经将 rpm 包上传到了机器上。
安装这四个包。
rpm -ivh clickhouse*.rpm
安装期间提示输入 default
用户密码,我这里将密码设置为:123456
。
你也可以直接按回车跳过。
安装完成后我们可以通过 rpm -qa | grep clickhouse
命令进行检查。
vim /etc/clickhouse-server/config.xml
打开文件后我们可以通过 :/listen
快速定位到需要修改的内容位置。
设置所有主机均可访问。
ClickHouse 的客户端默认端口为 9000
,JDBC 连接的默认端口为 8123
。如果你是在集群中使用有可能会产生端口冲突的情况,我们同样可以在该文件中进行修改。
可以通过 :/tcp_port
快速定位到需要修改的客户端默认端口的内容位置。
可以通过 :/http_port
快速定位到需要修改的 JDBC 连接默认端口的内容位置。
# 启动 ClickHouse
clickhouse start
# 查看状态
clickhouse status
# 停止
clickhouse stop
ClickHouse 安装后会默认设置为开机自启动,如果想要关闭开机自启动可以执行如下命令:
systemctl disable clickhouse-server
客户端默认端口为 9000
,JDBC 连接默认端口为:8123
。
clickhouse-client -m --password 123456
参数解析:
-m
表示命令允许进行换行,以分号 ;
作为语句结束符。不添加该参数则按下回车时就会执行语句。--password
安装期间设置的密码,如果没设置密码就不需要指定该参数。查询所有库:show databases;
退出命令:quit;
非交互式查询:clickhouse-client --password 123456 --query "show databases;"
引擎名称 | 说明 |
---|---|
MergeTree | 适用于查询性能要求较高的数据表,如:时间序列数据。它有一个优化排序和合并的技术,从而提高数据查询速度。 |
CollapsingMergeTree | 与 MergeTree 相似,但是在累加数据值方面更有优势。它可以在查询中合并多个数据值。 |
SummingMergeTree | 与 CollapsingMergeTree 相似,但它专门用于对数值累加。 |
ReplacingMergeTree | 适用于在数据表中替换某些数据值。如果数据表中存在与新数据重复的键,则它将替换该数据。 |
GraphiteMergeTree | 适用于操作时间序列数据,如:Graphite 应用。它对时间序列数据查询具有较高的性能。 |
VersionedCollapsingMergeTree | 适用于数据版本控制,并且可以在多个版本之间查询数据。 |
Memory | 将数据存储在 RAM 中,因此数据查询速度比磁盘存储快得多。不过,由于它是在内存中存储数据,因此它通常不适用于大数据量的数据表。 |
Buffer | 缓存引擎,用于存储缓存表。适用于中间结果,可以在内存和磁盘之间快速切换 相对于内存引擎的读写速度较慢,数据不能永久保存。 |
Int8, Int16, Int32, Int64: 这些数据类型都是有符号整数,分别对应二进制的 8 位,16 位,32 位和 64 位的整数。它们可以存储正整数和负整数。
Float32, Float64: 这两种数据类型分别对应单精度和双精度浮点数。它们可以存储带有小数部分的数字。
String: 这是一种字符串类型,可以存储 UTF-8 编码的字符串。字符串长度最大为 2^64-1。
Date: 这是一种日期类型,用于存储日期信息(年月日)。
DateTime: 这是一种日期和时间类型,用于存储日期和时间信息(年月日时分秒)。
Enum8, Enum16: 这是一种枚举类型,用于存储一个固定的值的集合中的一个元素。Enum8 可以存储最多 256 个元素,Enum16 可以存储最多 65536 个元素。
FixedString(N): 这是一种固定长度的字符串类型,可以存储 N 个字符,其中 N 是一个正整数。
IPV4, IPV6: 这是两种 IP 地址类型,分别用于存储 IPv4 和 IPv6 地址。
LowCardinality(T): 这是一种低基数类型,用于存储具有有限数量可能值的字段,如性别(男,女)。其中 T 是其他类型(如 UInt8,Int16 等)。
Tuple(…): 这是一种元组类型,用于存储多个值的集合,每个值都具有不同的数据类型。
Array(T): 这是一种数组类型,用于存储具有相同数据类型的多个值的集合。其中 T 是其他
Decimal(P,S),Decimal32(S),Decimal64(S),Decimal128(S):有符号的定点数,可在加、减和乘法运算过程中保持精度。对于除法,最低有效数字会被丢弃(不舍入)。
建表示例:
CREATE TABLE example_table (
id UInt32,
name String,
score Float32,
grade Enum8('A' = 0, 'B' = 1, 'C' = 2, 'D' = 3, 'E' = 4, 'F' = 5),
birthdate Date,
birthdatetime DateTime,
gender LowCardinality(String),
ip_address IPv4,
char_array Array(String),
tuple_field Tuple(UInt8, Int16, Float32)
) ENGINE = Memory;
INSERT INTO example_table (id, name, score, grade, birthdate, birthdatetime, gender, ip_address, char_array, tuple_field)
VALUES
(1, 'John Doe', 89.5, 'B', '2000-01-01', '2000-01-01 12:00:00', 'Male', '192.168.0.1', ['a', 'b', 'c'], (1, 2, 3.14)),
(2, 'Jane Doe', 92.0, 'A', '2000-02-02', '2000-02-02 12:00:00', 'Female', '192.168.0.2', ['d', 'e', 'f'], (4, 5, 6.28)),
(3, 'John Smith', 77.0, 'C', '2000-03-03', '2000-03-03 12:00:00', 'Male', '192.168.0.3', ['g', 'h', 'i'], (7, 8, 9.42));
pom
文件中添加连接依赖:
<dependency>
<groupId>com.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.4.0</version>
<classifier>all</classifier>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
在 ClickHouse 中创建测试库表。
create database if not exists test;
use test;
drop table if exists student;
create table student(
id Int16,
name String,
sex String,
age Int8,
class String)
ENGINE=MergeTree
partition by(class)
order by (id);
-- 插入数据时字符串必须使用单引号,否则会报错。
insert into student values(1,'张三','male',20,'A'),(2,'李四','male',21,'A'),(3,'王五','male',20,'A');
select * from student;
核心代码:
val spark: SparkSession = SparkSession.builder().appName("ReadTest").master("local[*]").getOrCreate()
spark.read.format("jdbc")
.option("driver", "com.clickhouse.jdbc.ClickHouseDriver") // clickhouse 连接驱动
.option("url", "jdbc:clickhouse://192.168.10.10:8123/test") // 指定 clickhouse 连接库
.option("user", "default") // 用户名
.option("password", "123456") // 密码
.option("dbtable","student") // 连接表
.load()
.orderBy("id")
.show()
spark.stop()
注意!其中的参数修改为自己的值。
输出结果:
我们先创建一个文本文件 students.txt
,添加如下内容,模拟写入的数据:
4 Jack male 20 B
5 Tom male 22 B
6 Lily female 21 B
间隔符为空格。
核心代码:
val spark: SparkSession = SparkSession.builder().appName("WriteTest").master("local[*]").getOrCreate()
spark.read
.text("students.txt")
.createOrReplaceTempView("data")
val dataFrame: DataFrame = spark.sql(
"""
|select
| split(value," ")[0] id,
| split(value," ")[1] name,
| split(value," ")[2] sex,
| split(value," ")[3] age,
| split(value," ")[4] class
|from data
|""".stripMargin)
dataFrame.write.format("jdbc")
.option("driver", "com.clickhouse.jdbc.ClickHouseDriver") // clickhouse 连接驱动
.option("url", "jdbc:clickhouse://192.168.10.10:8123/test") // 指定 clickhouse 连接库
.option("user", "default") // 用户名
.option("password", "123456") // 密码
.option("dbtable","student") // 连接表,该表必须存在!否则会报错
.mode(SaveMode.Append) // 以追加的模式写入数据
.save()
spark.stop()
我们可以进入 ClickHouse 或者再次运行读取 ClickHouse 数据的程序进行验证。
如果你需要将打好的 jar 包放到集群上运行,需要提前在 spark 的 jars 目录中添加一个 ClickHouse 的连接驱动包,本文中使用的连接驱动版本为 0.4.0
,下载地址如下:
注意,必须是 clickhouse-jdbc-0.4.0-all.jar
,而不是 clickhouse-jdbc-0.4.0.jar
!