安装ClickHouse并和SpringBoot、Mybatisplus整合,实现千万级数据查询优化
引言
线上产生数据越来越多,MySQL数据库查询越来越慢,常规优化如分库分表、添加索引、使用缓存、优化代码查询逻辑已经无法实现优化(真实情况是功能能做出来就不错了,优化代码不存在的,什么?分库分表?改表结构?历史数据怎么割接处理?能不能尽量不改原有的逻辑加些什么中间件实现效果?),带着这些需求上网查了资料,最终决定使用ClickHouse来优化查询速度,具体设计是:MySQL还是作为业务库持久化存储数据,DML操作对MySQL,DQL操作使用ClickHouse,并且使用ClickHouse自带的数据库引擎MaterializedMySQL实现MySQL到ClickHouse的数据同步。
本文安装部署一个单机ClickHouse,和SpringBoot、Mybatisplus集成,测试查询千万级数据效果并和直接查询MySQL数据库对比,以此来体会ClickHouse的强悍。
一、安装ClickHouse
官网安装教程链接:clickhouse.com/docs/zh/get…
我是Centos,安装过程如下:
1.安装
yum install -y yum-utils
yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo
yum install -y clickhouse-server clickhouse-client
2.启动
/etc/init.d/clickhouse-server start
# 查看是否启动成功
ps -ef|grep clickhouse
# 命令行登录(默认没有密码)
clickhouse-client
3.修改密码并配置远程连接
# 修改密码(注:只读文件,退出时命令: wq!)
vim /etc/clickhouse-server/users.xml
# 配置远程访问(注:只读文件,退出时命令: wq!)
vim /etc/clickhouse-server/config.xml
4.使用密码重新连接
/etc/init.d/clickhouse-server stop
/etc/init.d/clickhouse-server start
clickhouse-client --password 123456
5.可以访问ClickHouse自带的UI界面
http://部署ClickHouse服务器IP:8123/play
二、开启MySQL的binlog并且配置ClickHouse的MaterializedMySQL引擎实现MySQL到ClickHouse的数据同步
1.修改MySQL的配置文件my.cnf开启binlog
重启MySQL使用命令查看是否正确开启
# 登录MySQL
docker exec -it 08a438ea4dff bash
mysql -u root -p数据库密码
show variables like '%log_bin%';
2.ClickHouse使用MaterializedMySQL引擎
CREATE DATABASE mysql_db ENGINE = MaterializedMySQL('MySQL数据库服务器ip:MySQL数据库服务器端口', '要同步的MySQL数据库库名', 'MySQL数据库用户名', 'MySQL数据库密码');
如果出现这个报错,先执行以下命令,再重新在ClickHouse创建数据库
set allow_experimental_database_materialized_mysql=1;
可以看到数据库已经从MySQL同步过来了
三、SpringBoot+MyBatisplus+ClickHouse、MySQL整合对比查询千万级数据速度
1.新建一个SpringBoot项目
pom配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>ru.yandex.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.23</version>
</dependency>
yml配置
server:
port: 8888
spring:
datasource:
dynamic:
primary: master
datasource:
master:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://MySQL的ip:MySQL的端口/clickhouse_test?characterEncoding=UTF-8&serverTimezone=GMT%2B8&allowMultiQueries=true
username: MySQL的用户名
password: MySQL的密码
slave:
driver-class-name: ru.yandex.clickhouse.ClickHouseDriver
url: jdbc:clickhouse://ClickHouse的ip:8123/mysql_db
username: default
password: ClickHouse的密码
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
logging:
level:
com.zc.hadoop_hdfs_test.mapper: DEBUG
2.使用存储过程在MySQL数据库生成大量测试数据
# 创建测试表
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` tinyint(4) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5649324 DEFAULT CHARSET=utf8mb4
# 创建生成测试数据的存储过程
DELIMITER $$
USE `clickhouse_test`$$
DROP PROCEDURE IF EXISTS `proc_batch_insert`$$
CREATE DEFINER=`root`@`%` PROCEDURE `proc_batch_insert`()
BEGIN
DECLARE pre_name BIGINT;
DECLARE ageVal INT;
DECLARE i INT;
SET pre_name=187635267;
SET ageVal=100;
SET i=1;
WHILE i <= 20000000 DO
INSERT INTO t_user(`name`,age,create_time,update_time) VALUES(CONCAT(pre_name,'@qq.com'),(ageVal+i)%30,NOW(),NOW());
SET pre_name=pre_name+100;
SET i=i+1;
END WHILE;
END$$
DELIMITER ;
# 数量自定义,我现在定的两千万
# 执行存储过程
call proc_batch_insert();