ClickHouse學習系列之八【資料匯入遷移&同步】

jyzhou 發表於 2021-07-22

背景

  在介紹了一些ClickHouse相關的系列文章之後,大致對ClickHouse有了比較多的瞭解。它是一款非常優秀的OLAP資料庫,為了更好的來展示其強大的OLAP能力,本文將介紹一些快速匯入大量資料到ClickHouse的方法。如:通過檔案、遠端資料庫等方式。

說明

一、其他資料庫匯入到ClickHouse

MySQL可以做為ClickHouse的外部儲存型別,還有其他的儲存型別,如:MongoDB、PostgreSQL、HDFS、JDBC、ODBC、Kafka、File、RabbitMQ、S3等等,具體的可以看官網說明。本文介紹MySQL、MongoDB、File三種方式的匯入,前2種方式相當於連結串列。

① MySQL資料匯入到ClickHouse

方法一: 外部引擎,建立遠端表

MySQL引擎允許對儲存在遠端 MySQL 伺服器上的資料執行 SELECT 和 INSERT 查詢,不能執行DELETE 和 UPDATE。

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],
    ...
) ENGINE = MySQL('host:port', 'database', 'table', 'user', 'password'[, replace_query, 'on_duplicate_clause'])
SETTINGS
    [connection_pool_size=16, ]
    [connection_max_tries=3, ]
    [connection_auto_close=true ]
;

建議:列名相同。引數 external_table_functions_use_nulls 表示如何處理null值,預設1,可選值0。1:可以為null,0:不能為null,使用預設值代替。MySQL的引數說明:

  • host:port — MySQL 地址

  • database — MySQL資料庫名

  • table — MySQL表名

  • user — MySQL 使用者

  • password — MySQL使用者密碼

  • replace_query — 預設0,對應replace into。設定1這會用replace into 代替 insert into

  • on_duplicate_clause — 預設0,對應 ON DUPLICATE KEY。設定1這會代替 insert into,和replace_query互斥

例子:

CREATE TABLE testdb.test
(
    `id` UInt32,
    `c1` Date COMMENT 'c1',
    `c2` DateTime COMMENT 'c2',
    `c3` String COMMENT 'c3',
    `c4` UInt32 COMMENT 'c4'
)
ENGINE = MySQL('10.10.10.10:3306','test','test','dba','dba')

注意:在查詢遠端表的時候,除了where條件會帶入到遠端的MySQL中,其餘的條件(聚合),包含limit都會在ClickHouse本地執行,而遠端則執行全表掃描。最後可以對該表執行 SELECT 和 INSERT 查詢,不能執行DELETE 和 UPDATE。

此後就可以在ClickHouse上建立符合要求的引擎表,如MergeTree引擎,再通過以下SQL來進行匯入資料。

 insert into ck_tb select * from my_tb

 方法二:和方法一類似,不過方法二是直接用了mysql函式來進行遠端訪問:建立需要的引擎,再用mysql函式進行遠端匯入,可以指定列來匯入資料,把*改成具體列名。

insert into ck_tb select * from mysql('host:port', 'database', 'table', 'user', 'password')

mysql函式裡的引數可以參考方法一的說明。
例子:

-- 建立表
CREATE TABLE testdb.test_ck1
(
    `id` UInt32,
    `c1` Date COMMENT 'c1',
    `c2` DateTime COMMENT 'c2',
    `c3` String COMMENT 'c3',
    `c4` UInt32 COMMENT 'c4'
)
ENGINE = MergeTree
PARTITION BY c1
ORDER BY id

-- 插入資料
INSERT INTO test_ck1 SELECT *
FROM mysql('10.10.10.10:3306','test','test','dba','dba')

方法三:create + select

CREATE TABLE [IF NOT EXISTS] [db.]table_name
ENGINE = ENGINE
AS
SELECT *
FROM mysql('host:port', 'database', 'table', 'user', 'password')

mysql函式裡的引數可以參考方法一的說明。

例子:

create table test_ck2 engine = MergeTree order by id as select * from mysql('10.10.10.10:3306','test','test','dba','dba');
或
create table test_ck2 engine = Log as select * from mysql('10.10.10.10:3306','test','test','dba','dba');

通過該方法的匯入,不需要事先建立表,它會自動根據select出來的資料按照需要建立符合要求的型別。

② MongoDB資料匯入到ClickHouse

MongoDB引擎允許對儲存在遠端 MongoDB 伺服器上的資料執行 SELECT 查詢,不能執行 INSERT、DELETE 和 UPDATE。

CREATE TABLE [IF NOT EXISTS] [db.]table_name
(
    name1 [type1],
    name2 [type2],
    ...
) ENGINE = MongoDB(host:port, database, collection, user, password);

建議:列名相同。MongoDB的引數說明:

  • host:port — MongoDB 地址.

  • database — MongoDB 資料庫名

  • collection — MongoDB 集合名

  • user — MongoDB 使用者

  • password — MongoDB 密碼

例子:

CREATE TABLE mongo_table
(
    key UInt64, 
    data String
) ENGINE = MongoDB('mongo1:27017', 'test', 'simple_table', 'testuser', 'clickhouse');

注意:相對於MySQL,MongoDB遠端表還不允許INSERT。此後就可以在ClickHouse上建立符合要求的引擎表,如MergeTree引擎,再通過以下SQL來進行匯入資料。

insert into ck_tb select * from mon_tb

MongoDB目前只作為一個外部引擎,不像MySQL還能作為一個函式進行遠端操作,所以MySQL資料處理中的方法二、三不適用於MongoDB資料的處理。

③ File資料匯入到ClickHouse外部引擎函式

和MySQL引擎匯入方法類似, 支援併發讀,不支援併發插入。不支援ALTER、索引和副本

方法一:外部引擎(建立遠端表)

CREATE TABLE file_engine_table (name String, value UInt32) ENGINE=File(Format)

File函式裡的引數Format的取值可以看文件,這裡說明下csv的例子。

-- 建立表
create table csv_table(id UInt64,name String)engine = File('CSV');

-- 在表目錄裡建立檔案或則匯入檔案,必須命名為data.CSV
$ cat data.CSV 
1,a
2,b
3,c
4,d
5,e

-- 這樣,在表裡就可以看到資料了
:) select * from csv_table;

┌─id─┬─name─┐
│  1 │ a    │
│  2 │ b    │
│  3 │ c    │
│  4 │ d    │
│  5 │ e    │
└────┴──────┘

注意:File引擎的表,可以對其進行SELECT、INSERT,不能進行DELETE、UPDATE。此後就可以在ClickHouse上建立符合要求的引擎表,如MergeTree引擎,再通過以下SQL來進行匯入資料。

insert into ck_tb select * from csv_tb

方法二: 

通過file函式匯入資料,並且以表的形式展示,格式為:

select * from file(path, format, structure)
  • path — 引數user_files_path下的相對路徑,支援以下格式:*、?、{abc,def} 和 {N..M} ,其中 N、M — 數字、'abc'、'def' — 字串。
  • format — 檔案格式
  • structure — 表結構。 格式:'column1_name column1_type, column2_name column2_type, ...'

在config.xml檔案中找到引數user_files_path,在該引數指定的目錄下建立一個csv檔案:

$ cat test.csv 
1,a,123
2,b,234
3,c,345
4,d,456
5,e,567

然後通過SQL查詢:

:) SELECT * FROM file('test.csv', 'CSV', 'column1 UInt32, column2 String, column3 UInt32');
┌─column1─┬─column2─┬─column3─┐
│       1 │ a       │     123 │
│       2 │ b       │     234 │
│       3 │ c       │     345 │
│       4 │ d       │     456 │
│       5 │ e       │     567 │
└─────────┴─────────┴─────────┘

如果該目錄下有多個csv檔案:test.csv、test1.csv、test2.csv,則可以通過萬用字元來進行全部載入讀取:

:) SELECT * FROM file('test*.csv', 'CSV', 'column1 UInt32, column2 String, column3 UInt32');

┌─column1─┬─column2─┬─column3─┐
│       1 │ aaa     │     123 │
│       2 │ bbb     │     234 │
│       3 │ ccc     │     345 │
│       4 │ ddd     │     456 │
│       5 │ eee     │     567 │
└─────────┴─────────┴─────────┘
┌─column1─┬─column2─┬─column3─┐
│       1 │ a       │     123 │
│       2 │ b       │     234 │
│       3 │ c       │     345 │
│       4 │ d       │     456 │
│       5 │ e       │     567 │
└─────────┴─────────┴─────────┘
┌─column1─┬─column2─┬─column3─┐
│       1 │ aa      │     123 │
│       2 │ bb      │     234 │
│       3 │ cc      │     345 │
│       4 │ dd      │     456 │
│       5 │ ee      │     567 │
└─────────┴─────────┴─────────┘

此後就可以在ClickHouse上建立符合要求的引擎表,如MergeTree引擎,再通過以下SQL來進行匯入資料。

:) insert into csv_table_ck SELECT * FROM file('test*.csv', 'CSV', 'column1 UInt32, column2 String, column3 UInt32')

方法三: create + select

CREATE TABLE [IF NOT EXISTS] [db.]table_name
ENGINE = ENGINE 
AS
SELECT *
FROM file(path, format, structure)

例子:

:) create table csv_table_ck1 engine = MergeTree ORDER BY column1 as  SELECT * FROM file('test*.csv', 'CSV', 'column1 UInt32, column2 String, column3 UInt32');

注意:需要在file函式的引數structure指定的表結構欄位中選取欄位進行 ORDER BY 的指定設定。並且通過該方法的匯入,不需要事先建立表,它會自動根據select出來的資料按照需要建立符合要求的型別。

方法四:也可以通過輸入流來進行資料的匯入,clickhouse-local 

$ echo -e "1,2\n3,4" | clickhouse-local -q "CREATE TABLE table (a Int64, b Int64) ENGINE = File(CSV, stdin); SELECT a, b FROM table; DROP TABLE table"

二、MySQL同步到ClickHouse(實驗階段)

ClickHouse推出了MaterializeMySQL資料庫引擎,用於將MySQL伺服器中的表對映到ClickHouse中。ClickHouse服務做為MySQL副本,讀取Binlog並執行DDL和DML請求,實現了基於MySQL Binlog機制的業務資料庫實時同步功能:支援全量和增量同步,首次建立資料庫引擎時進行一次全量複製,之後通過監控binlog變化進行增量資料同步。阿里雲上也有介紹說明

CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster]
ENGINE = MaterializeMySQL('host:port', ['database' | database], 'user', 'password') [SETTINGS ...]
  • host:port — MySQL 地址
  • database — MySQL 資料庫名
  • user — MySQL 使用者名稱,具有MySQL庫的RELOAD、REPLICATION SLAVE、REPLICATION CLIENT以及SELECT PRIVILEGE許可權
  • password — MySQL 密碼

使用MaterializeMySQL資料庫引擎,同步到ClickHouse叢集上表的預設引擎為ReplacingMergeTree,並會在表中增加2個虛擬列:

  • _version — 事務計數器,記錄資料版本資訊。UInt64型別。
  • _sign — 刪除標記,標記該行是否刪除。TypeInt8型別:
    • 1 — 未刪除
    • -1 — 已刪除

測試:

MaterializeMySQL資料庫引擎需要開啟allow_experimental_database_materialize_mysql引數。即需要設定為1:

SET allow_experimental_database_materialize_mysql = 1

以上SET 只是更改了當前會話中的值,分散式 DDL 在單獨的會話中執行,SET 不影響它。 應該在伺服器配置中全域性啟用 allow_experimental_database_materialize_mysql 設定,如:

 修改user.xml:

    <profiles>
        <!-- Default settings. -->
        <default>
...
            <allow_experimental_database_materialize_mysql>1</allow_experimental_database_materialize_mysql>
        </default>
...
    </profiles>

修改config.xml: 

    <distributed_ddl>
...
        <path>/clickhouse/task_queue/ddl</path>
        <allow_experimental_database_materialize_mysql>1</allow_experimental_database_materialize_mysql>
...
    </distributed_ddl>

修改這些配置是動態生效的,可以檢視該引數是否修改成功: 

:) SELECT * FROM system.settings WHERE name = 'allow_experimental_database_materialize_mysql';

┌─name──────────────────────────────────────────┬─value─┬─changed─┬─description─────────────────────────────────────────────────┬─min──┬─max──┬─readonly─┬─type─┐
│ allow_experimental_database_materialize_mysql │ 11 │ Allow to create database with Engine=MaterializeMySQL(...). │ ᴺᵁᴸᴸ │ ᴺᵁᴸᴸ │        0 │ Bool │
└───────────────────────────────────────────────┴───────┴─────────┴─────────────────────────────────────────────────────────────┴──────┴──────┴──────────┴──────┘

現在可以開始MaterializeMySQL資料庫引擎來同步MySQL資料庫了。需要注意的是MySQL的binlog格式為Row,並且開啟GTID。

①:建立MaterializeMySQL資料庫:同步MySQL的ck_test庫中的表

:) create database mysql_2_ck ENGINE = MaterializeMySQL('10.10.10.10:3306','ck_test','test','test');

②:全量同步

-- 全量:
通過 select * from tb 拉取MySQL的全量資料進行同步,再在本地ClickHouse上回放

③:增量同步

-- 增量:
通過訂閱MySQL binlog來進行增量同步,在mysql上可以看到 Binlog Dump GTID 的訂閱執行緒,再在本地ClickHouse上回放

④:記錄MySQL Binlog資訊 

-- 記錄 binlog 資訊<path>指定的目錄下的metadata/dbname中儲存binlog和position:<path>/metadata/dbname/.metadata

通過①~⑤同步關係已經搭建完成,為了測試同步效果,進行測試:測試同步包括:insert,update,delete,alter,create,drop,truncate等大部分DML和DDL操作

說明:在①中已經建立了ClickHouse【mysql_2_ck】和MySQL【ck_test】庫的同步,後續操作在該庫中進行。

新建表
-- mysql> CREATE TABLE employees (
    ->     emp_no      INT             NOT NULL,
    ->     birth_date  DATE            NOT NULL,
    ->     first_name  VARCHAR(14)     NOT NULL,
    ->     last_name   VARCHAR(16)     NOT NULL,
    ->     gender      CHAR(3)         NOT NULL,    
    ->     hire_date   DATE            NOT NULL,
    ->     PRIMARY KEY (emp_no)
    -> ) ENGINE=INNODB;

-- clickhouse :) show create table employees\G
statement: CREATE TABLE mysql_2_ck.employees
(
    `emp_no` Int32,
    `birth_date` Date,
    `first_name` String,
    `last_name` String,
    `gender` String,
    `hire_date` Date,
    `_sign` Int8 MATERIALIZED 1,
    `_version` UInt64 MATERIALIZED 1,
    INDEX _version _version TYPE minmax GRANULARITY 1
)
ENGINE = ReplacingMergeTree(_version)
PARTITION BY intDiv(emp_no, 4294967)
ORDER BY tuple(emp_no)
SETTINGS index_granularity = 8192


新增資料
-- mysql> INSERT INTO `employees` VALUES (10001,'1953-09-02','Georgi','Facello','M','1986-06-26'),
    -> (10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21'),
    -> (10003,'1959-12-03','Parto','Bamford','M','1986-08-28'),
    -> (10004,'1954-05-01','Chirstian','Koblick','M','1986-12-01'),
    -> (10005,'1955-01-21','Kyoichi','Maliniak','M','1989-09-12'),
    -> (10006,'1953-04-20','Anneke','Preusig','F','1989-06-02'),
    -> (10007,'1957-05-23','Tzvetan','Zielinski','F','1989-02-10'),
    -> (10008,'1958-02-19','Saniya','Kalloufi','M','1994-09-15'),
    -> (10009,'1952-04-19','Sumant','Peac','F','1985-02-18'),
    -> (10010,'1963-06-01','Duangkaew','Piveteau','F','1989-08-24'),
    -> (10011,'1953-11-07','Mary','Sluis','F','1990-01-22'),
    -> (10012,'1960-10-04','Patricio','Bridgland','M','1992-12-18'),
    -> (10013,'1963-06-07','Eberhardt','Terkki','M','1985-10-20'),
    -> (10014,'1956-02-12','Berni','Genin','M','1987-03-11'),
    -> (10015,'1959-08-19','Guoxiang','Nooteboom','M','1987-07-02'),
    -> (10016,'1961-05-02','Kazuhito','Cappelletti','M','1995-01-27'),
    -> (10017,'1958-07-06','Cristinel','Bouloucos','F','1993-08-03'),
    -> (10018,'1954-06-19','Kazuhide','Peha','F','1987-04-03');

-- clickhouse :) select * from mysql_2_ck.employees;
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name───┬─gender─┬──hire_date─┐
│  100022143-11-07 │ Bezalel    │ Simmel      │ F      │ 1985-11-21 │
│  100062132-09-24 │ Anneke     │ Preusig     │ F      │ 1989-06-02 │
│  100112133-04-13 │ Mary       │ Sluis       │ F      │ 1990-01-22 │
│  100152139-01-23 │ Guoxiang   │ Nooteboom   │ M      │ 1987-07-02 │
│  100162140-10-06 │ Kazuhito   │ Cappelletti │ M      │ 1995-01-27 │
└────────┴────────────┴────────────┴─────────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100042133-10-05 │ Chirstian  │ Koblick   │ M      │ 1986-12-01 │
│  100092131-09-24 │ Sumant     │ Peac      │ F      │ 1985-02-18 │
│  100132142-11-11 │ Eberhardt  │ Terkki    │ M      │ 1985-10-20 │
│  100182133-11-23 │ Kazuhide   │ Peha      │ F      │ 1987-04-03 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100032139-05-09 │ Parto      │ Bamford   │ M      │ 1986-08-28 │
│  100072136-10-27 │ Tzvetan    │ Zielinski │ F      │ 1989-02-10 │
│  100102142-11-05 │ Duangkaew  │ Piveteau  │ F      │ 1989-08-24 │
│  100142135-07-19 │ Berni      │ Genin     │ M      │ 1987-03-11 │
│  100172137-12-10 │ Cristinel  │ Bouloucos │ F      │ 1993-08-03 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100012133-02-06 │ Georgi     │ Facello   │ M      │ 1986-06-26 │
│  100052134-06-27 │ Kyoichi    │ Maliniak  │ M      │ 1989-09-12 │
│  100082137-07-26 │ Saniya     │ Kalloufi  │ M      │ 1994-09-15 │
│  100122140-03-10 │ Patricio   │ Bridgland │ M      │ 1992-12-18 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘


刪除資料
-- mysql> delete from employees where emp_no >10010;
Query OK, 8 rows affected (0.01 sec)

-- clickhouse :) select * from mysql_2_ck.employees;
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100012133-02-06 │ Georgi     │ Facello   │ M      │ 1986-06-26 │
│  100052134-06-27 │ Kyoichi    │ Maliniak  │ M      │ 1989-09-12 │
│  100082137-07-26 │ Saniya     │ Kalloufi  │ M      │ 1994-09-15 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100042133-10-05 │ Chirstian  │ Koblick   │ M      │ 1986-12-01 │
│  100092131-09-24 │ Sumant     │ Peac      │ F      │ 1985-02-18 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100032139-05-09 │ Parto      │ Bamford   │ M      │ 1986-08-28 │
│  100072136-10-27 │ Tzvetan    │ Zielinski │ F      │ 1989-02-10 │
│  100102142-11-05 │ Duangkaew  │ Piveteau  │ F      │ 1989-08-24 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100022143-11-07 │ Bezalel    │ Simmel    │ F      │ 1985-11-21 │
│  100062132-09-24 │ Anneke     │ Preusig   │ F      │ 1989-06-02 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘


修改資料
-- mysql> update employees set hire_date = hire_date+1 where emp_no <10005;
Query OK, 4 rows affected (0.01 sec)

-- clickhouse :) select * from mysql_2_ck.employees;
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100012133-02-06 │ Georgi     │ Facello   │ M      │ 1986-06-27 │
│  100052134-06-27 │ Kyoichi    │ Maliniak  │ M      │ 1989-09-12 │
│  100082137-07-26 │ Saniya     │ Kalloufi  │ M      │ 1994-09-15 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100032139-05-09 │ Parto      │ Bamford   │ M      │ 1986-08-29 │
│  100072136-10-27 │ Tzvetan    │ Zielinski │ F      │ 1989-02-10 │
│  100102142-11-05 │ Duangkaew  │ Piveteau  │ F      │ 1989-08-24 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100022143-11-07 │ Bezalel    │ Simmel    │ F      │ 1985-11-22 │
│  100062132-09-24 │ Anneke     │ Preusig   │ F      │ 1989-06-02 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘
┌─emp_no─┬─birth_date─┬─first_name─┬─last_name─┬─gender─┬──hire_date─┐
│  100042133-10-05 │ Chirstian  │ Koblick   │ M      │ 1986-12-02 │
│  100092131-09-24 │ Sumant     │ Peac      │ F      │ 1985-02-18 │
└────────┴────────────┴────────────┴───────────┴────────┴────────────┘


修改表結構
- 新增欄位
-- mysql> alter table employees add age int after gender;
Query OK, 0 rows affected (0.08 sec)

-- clickhouse :) desc mysql_2_ck.employees;
┌─name───────┬─type────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ emp_no     │ Int32           │              │                    │         │                  │                │
│ birth_date │ Date            │              │                    │         │                  │                │
│ first_name │ String          │              │                    │         │                  │                │
│ last_name  │ String          │              │                    │         │                  │                │
│ gender     │ String          │              │                    │         │                  │                │
│ age        │ Nullable(Int32) │              │                    │         │                  │                │
│ hire_date  │ Date            │              │                    │         │                  │                │
│ _sign      │ Int8            │ MATERIALIZED │ 1                  │         │                  │                │
│ _version   │ UInt64          │ MATERIALIZED │ 1                  │         │                  │                │
└────────────┴─────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘

- 刪除欄位
-- mysql> alter table employees drop age;
Query OK, 0 rows affected (0.09 sec)

-- clickhouse :) desc mysql_2_ck.employees;
┌─name───────┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ emp_no     │ Int32  │              │                    │         │                  │                │
│ birth_date │ Date   │              │                    │         │                  │                │
│ first_name │ String │              │                    │         │                  │                │
│ last_name  │ String │              │                    │         │                  │                │
│ gender     │ String │              │                    │         │                  │                │
│ hire_date  │ Date   │              │                    │         │                  │                │
│ _sign      │ Int8   │ MATERIALIZED │ 1                  │         │                  │                │
│ _version   │ UInt64 │ MATERIALIZED │ 1                  │         │                  │                │
└────────────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘

新增索引
-- ClickHouse不會同步

刪除索引
-- ClickHouse不會同步

修改欄位長度
-加長
-- mysql> alter table employees modify age bigint;

-- clickhouse :) desc employees;
┌─name───────┬─type─────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ emp_no     │ Int32            │              │                    │         │                  │                │
│ birth_date │ Date             │              │                    │         │                  │                │
│ first_name │ String           │              │                    │         │                  │                │
│ last_name  │ String           │              │                    │         │                  │                │
│ gender     │ String           │              │                    │         │                  │                │
│ age        │ Nullable(Int64)  │              │                    │         │                  │                │
│ address    │ Nullable(String) │              │                    │         │                  │                │
│ hire_date  │ Date             │              │                    │         │                  │                │
│ _sign      │ Int8             │ MATERIALIZED │ 1                  │         │                  │                │
│ _version   │ UInt64           │ MATERIALIZED │ 1                  │         │                  │                │
└────────────┴──────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘

-改短
-- mysql> alter table employees modify age int;

-- clickhouse :) desc employees;
┌─name───────┬─type─────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ emp_no     │ Int32            │              │                    │         │                  │                │
│ birth_date │ Date             │              │                    │         │                  │                │
│ first_name │ String           │              │                    │         │                  │                │
│ last_name  │ String           │              │                    │         │                  │                │
│ gender     │ String           │              │                    │         │                  │                │
│ age        │ Nullable(Int32)  │              │                    │         │                  │                │
│ address    │ Nullable(String) │              │                    │         │                  │                │
│ hire_date  │ Date             │              │                    │         │                  │                │
│ _sign      │ Int8             │ MATERIALIZED │ 1                  │         │                  │                │
│ _version   │ UInt64           │ MATERIALIZED │ 1                  │         │                  │                │
└────────────┴──────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘

修改欄位名
-- ClickHouse 不支援,同步報錯

修改欄位備註
-- ClickHouse 不會同步

清空表
-- mysql> truncate table employees;
Query OK, 0 rows affected (0.02 sec)

-- ClickHouse:) select * from mysql_2_ck.employees;
0 rows in set. Elapsed: 0.002 sec. 

重新命名錶
-- ClickHouse 正常同步

刪除表
-- ClickHouse 正常同步

在測試中發現有以下幾個情況會導致複製同步異常,可能不全,後續有情況會繼續更新,目前發現的有:

  • 沒有主鍵
  • 欄位型別為:Enum、bit、time、json
  • 修改欄位名

出現同步異常之後,會導致正常的ClickHouse上的表也不能讀取,修復則需要刪除整個庫,再重新同步。如果使用MaterializeMySQL同步MySQL,不允許以上導致同步異常的情況發生。

因為MaterializeMySQL目前屬於實驗階段,如果需要此功能,需要做好各種測試和驗證。

除了自帶的MaterializeMySQL可以同步MySQL資料之外,還可以用 Bifrost 來進行同步,該同步工具可以避免MaterializeMySQL同步欄位型別的問題,單也有一些限制。具體的可以看官方介紹,該工具支援支援全量,增量同步。

總結

本文介紹了幾種ClickHouse的匯入方法,以及MySQL同步到ClickHouse的方法,這種資料批量匯入和同步極大的方便了遷移資料的成本。後期官方如果完善MaterializeMySQL,相信ClickHouse將會進一步提高在OLAP上的使用率。