系统:CentOS
一、Clickhouse的单机部署
1.1 CentOS取消打开文件数限制
1.1.1 编辑/etc/security/limits.conf,文件的末尾加入以下内容。
[root@localhost ~]$ vim /etc/security/limits.conf
soft nofile 65536
hard nofile 65536
soft nproc 131072
hard nproc 131072
1.1.2 编辑/etc/security/limits.d/20-nproc.conf,文件的末尾加入以下内容。
[root@localhost ~]$ vim /etc/security/limits.d/20-nproc.conf
soft nofile 65536
hard nofile 65536
soft nproc 131072
hard nproc 131072
1.2 安装依赖
[root@localhost ~]$ sudo yum install -y libtool
[atguigu@hadoop102 ~]$ sudo yum install -y unixODBC
这里遇到第一个坑,服务器的yum命令不能正常运行。
解决方法:
出现这种原因是因为yum与python的版本不对应,因为yum是python的模块,而系统中又存在多个版本的python,所以会对应不上。
所以修改yum的配置,修改文件:
[root@localhost ~]$ vim /usr/bin/yum
#!/usr/bin/python => #!/usr/bin/python2.7
另外也要修改urlgrabber-ext-down使用的解释器,与yum的python版本统一。
[root@localhost ~]$ vim /usr/libexec/urlgrabber-ext-down
#!/usr/bin/python => #!/usr/bin/python2.7
1.3 CentOS取消SELINUX
[atguigu@hadoop102 ~]$ sudo vim /etc/selinux/config
SELINUX=disabled
1.4 安装
1.4.1 新建目录用于存放安装包
[root@localhost software]$ mkdir clickhouse
将安装所需的四个安装包上传到该目录下,之后安装。
[root@localhost software] ]$ sudo rpm -ivh *.rpm
sudo rpm -qa|grep clickhouse 查看安装情况
1.5 修改配置文件及启动
1.5.1 修改配置文件
[root@localhost clickhouse]$ sudo vim /etc/clickhouse-server/config.xml
把 <listen_host> ::</listen_host> 的注释打开,这样的话才能让 ClickHouse 被除本机以外的服务器访问。
1.5.2 启动server
[root@localhost clickhouse]$ sudo systemctl start clickhouse-server
1.5.3 使用client连接server
[root@localhost clickhouse]$ clickhouse-client –m
1.6 Dbeaver测试连接Clickhouse
这里需要注意的是,默认的用户名为default,密码为安装时设置的密码。
二、Clickhouse的基本知识和使用
2.1 表引擎
表引擎是 ClickHouse 的一大特色。可以说,表引擎决定了如何存储表的数据。
包括:
➢ 数据的存储方式和位置,写到哪里以及从哪里读取数据。
➢ 支持哪些查询以及如何支持。
➢ 并发数据访问。
➢ 索引的使用(如果存在)。
➢ 是否可以执行多线程请求。
➢ 数据复制参数。
表引擎的使用方式就是必须显式在创建表时定义该表使用的引擎,以及引擎使用的相关 参数。
2.1.1 TinyLog
以列文件的形式保存在磁盘上,不支持索引,没有并发控制。一般保存少量数据的小表, 生产环境上作用有限。可以用于平时练习测试用。
如: create table t_tinylog ( id String, name String) engine=TinyLog;
2.1.2 Memory
内存引擎,数据以未压缩的原始形式直接保存在内存当中,服务器重启数据就会消失。 读写操作不会相互阻塞,不支持索引。简单查询下有非常非常高的性能表现(超过 10G/s)。 一般用到它的地方不多,除了用来测试,就是在需要非常高的性能,同时数据量又不太大(上限大概 1 亿行)的场景。
2.1.3 MergeTree
ClickHouse 中最强大的表引擎当属 MergeTree(合并树)引擎及该系列(*MergeTree) 中的其他引擎,支持索引和分区,地位可以相当于 innodb 之于 Mysql。而且基于 MergeTree, 还衍生除了很多小弟,也是非常有特色的引擎。
建表语句
create table t_order_mt(
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime )
engine =MergeTree partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
插入数据
insert into t_order_mt values
(101,'sku_001',1000.00,'2020-06-01 12:00:00') ,
(102,'sku_002',2000.00,'2020-06-01 11:00:00'),
(102,'sku_004',2500.00,'2020-06-01 12:00:00'),
(102,'sku_002',2000.00,'2020-06-01 13:00:00'),
(102,'sku_002',12000.00,'2020-06-01 13:00:00'),
(102,'sku_002',600.00,'2020-06-02 12:00:00');
MergeTree 其实还有很多参数(绝大多数用默认值即可),但是三个参数是更加重要的, 也涉及了关于 MergeTree 的很多概念。
2.2 SQL操作
基本上来说传统关系型数据库(以 MySQL 为例)的 SQL 语句,ClickHouse 基本都支持,这里着重介绍 ClickHouse 与标准 SQL(MySQL)不一致的地方。
2.2.1 Insert
基本与标准 SQL(MySQL)基本一致
(1)标准 insert into [table_name] values(…),(….)
(2)从表到表的插入 insert into [table_name] select a,b,c from [table_name_2]
2.2.2 Update 和 Delete
ClickHouse 提供了 Delete 和 Update 的能力,这类操作被称为 Mutation 查询,它可以看 做 Alter 的一种。
虽然可以实现修改和删除,但是和一般的 OLTP 数据库不一样,Mutation 语句是一种很 “重”的操作,而且不支持事务。 “重”的原因主要是每次修改或者删除都会导致放弃目标数据的原有分区,重建新分区。
所以尽量做批量的变更,不要进行频繁小数据的操作。
删除操作
alter table t_order_smt delete where sku_id ='sku_001';
修改操作
alter table t_order_smt update total_amount=toDecimal32(2000.00,2) where id =102;
由于操作比较“重”,所以 Mutation 语句分两步执行,同步执行的部分其实只是进行新增数据新增分区和并把旧分区打上逻辑上的失效标记。直到触发分区合并的时候,才会删 除旧数据释放磁盘空间,一般不会开放这样的功能给用户,由管理员完成。
2.2.3 查询操作
ClickHouse 基本上与标准SQL差别不大
➢ 支持子查询
➢ 支持 CTE(Common Table Expression 公用表表达式 with 子句)
➢ 支持各种 JOIN,但是 JOIN 操作无法使用缓存,所以即使是两次相同的 JOIN 语句, ClickHouse 也会视为两条新 SQL
➢ 不支持自定义函数
➢ GROUP BY 操作增加了 with rollup\with cube\with total 用来计算小计和总计。
2.3 JDBC操作
与常规的数据库连接基本无区别,修改需要的jdbc连接驱动即可,这里给出连接查询案例。
<dependency>
<groupId>ru.yandex.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.2.6</version>
</dependency>
示例代码:
public class dbUtils {
public Connection con;
dbUtils() {
//直接过数据库clickhouse
String driver = "ru.yandex.clickhouse.ClickHouseDriver";
String url = "jdbc:clickhouse://10.70.21.159:8123/default";
String user = "default";
String password = "RS@2022";
try {
Class.forName(driver);
con = DriverManager.getConnection(url, user, password);
if (!con.isClosed()) {
System.out.println("Open DB Connection success");
}
}catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) {
dbUtils c = new dbUtils();
c.DBQuery("select * from t_order_mt");
System.exit(0);
}
void DBExecute(String sqlStr) {
try {
Statement statement = con.createStatement();
boolean result = statement.execute(sqlStr);
System.out.println("+++++ execute sql: "+sqlStr);
statement.close();
}catch(Exception e) {
e.printStackTrace();
}
}
void DBQuery(String sqlStr) {
try {
Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery(sqlStr);
int columnCount = rs.getMetaData().getColumnCount();
System.out.println("+++++ query sql: "+sqlStr);
while(rs.next()){
String result = "";
for (int i=0; i<columnCount; i++) {
result += "\t" + rs.getString(i+1);
}
System.out.println(result);
}
rs.close();
statement.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
结果集: