從ClickHouse導入
本文為您介紹如何遷移自建ClickHouse的數(shù)據(jù)庫表和數(shù)據(jù)至實時數(shù)倉Hologres上進行數(shù)據(jù)開發(fā)。
前提條件
開通Hologres,詳情請參見購買Hologres。
已有ClickHouse實例,并且安裝ClickHouse-Client工具,如需安裝請單擊ClickHouse-Client,安裝和使用詳情請參見Getting Started。
使用PSQL客戶端連接Hologres實例,詳情請參見PSQL客戶端。
背景信息
ClickHouse是一個用于聯(lián)機分析(OLAP)的列式數(shù)據(jù)庫管理系統(tǒng)。Hologres是阿里巴巴自主研發(fā)的一款交互式分析產(chǎn)品,支持亞秒級響應與高QPS,您可以從ClickHouse遷移表和數(shù)據(jù)至Hologres獲取更好的數(shù)據(jù)開發(fā)體驗。
Hologres與ClickHouse產(chǎn)品特性對比如下。
分類 | 對比項 | Clickhouse | Hologres |
產(chǎn)品 | 定位 | 流量分析 | 通用實時數(shù)倉:數(shù)據(jù)分析和在線服務。 |
寫入 | 存儲 | 列存 | 列存和行存。 |
寫入可見性 | 秒級(需要客戶端攢數(shù)據(jù)進行批處理,分布式表寫入依賴Shard數(shù)據(jù)復制完成) | 毫秒級(寫入自適應批處理,寫入即可查) | |
寫入性能 | 高 | 非常高 | |
明細存儲 | 支持 | 支持 | |
主鍵(Primary Key) | 非數(shù)據(jù)庫主鍵(不支持唯一性約束,僅用于索引+聚合) | 標準數(shù)據(jù)庫主鍵,支持唯一性約束。 | |
可更新 | 不完備,能力弱(不支持基于主鍵的高QPS更新)。 | 完整支持(支持基于主鍵的高QPS更新)。 | |
實時寫入 | Append |
| |
索引 |
|
說明 自動建有minmax、bloom filter、ngram等索引,對用戶透明。 | |
查詢 | 優(yōu)化器 | RBO(Rule-Based Optimizer) | CBO(Cost-Based Optimizer) |
聯(lián)邦查詢 | 支持(Engine支持HDFS、Kafka) | 支持(FDW直讀MaxCompute、Hive) | |
預聚合 | 支持(通過MergeTree) | 支持(存儲過程+定期調(diào)度) | |
高QPS點查 | 不支持 | 支持,QPS可達千萬以上。 | |
單表復雜查詢 | 性能好 | 性能好 | |
多表JOIN | 性能差 | 性能好 | |
SQL語法 | 自定義語法 | 兼容PostgreSQL,功能更豐富。 | |
WINDOW FUNCTION | 不支持 | 支持 | |
事務 | 事務ACID | 無(不保證寫入即可查,最終一致性) | 有限支持(支持DDL事務、單行事務、基于snapshot的可見性) |
復制 | 容災和備份 | 通過Replication實現(xiàn)(遠程ZK+CK) | 通過Binlog復制實現(xiàn)邏輯復制,通過底層機制實現(xiàn)物理復制。 |
高級功能 | Binlog | 無 | 提供Binlog |
向量檢索 | ClickHouse 22.8及以上版本支持 | 支持 | |
空間數(shù)據(jù) | 不支持 | 支持 | |
安全管理 | 自定義權(quán)限 | 兼容PG權(quán)限模型、豐富的權(quán)限控制、IP白名單、數(shù)據(jù)脫敏。 | |
存儲計算分離 | 不分離,單機容量限制 | 分離,存儲容量近乎無限。 | |
可用性 | 用戶手工處理Failover | Failover自動恢復 | |
運維 | 復雜(手工維護Shard分布) | 免運維 | |
生態(tài) | 數(shù)據(jù)接入 | Kafka、Flink、Spark、... | Flink、Spark、JDBC、DataX、… |
BI工具 | 支持對接少量BI工具(Tableau、Superset、...) | 兼容PostgreSQL生態(tài),支持對接100+主流BI工具。 |
數(shù)據(jù)類型映射
ClickHouse與Hologres的數(shù)據(jù)類型映射如下表所示。
類別 | ClickHouse | Hologres |
日期 | Date | Date |
DateTime | TIMESTAMPTZ | |
DateTime(timezone) | TIMESTAMPTZ | |
DateTime64 | TIMESTAMPTZ | |
數(shù)值 | Int8 | 不支持單字節(jié)INT,可選SMALLINT。 |
Int16 | SMALLINT | |
Int32 | INT | |
Int64 | BIGINT | |
UInt8 | INT | |
UInt16 | INT | |
UInt32 | BIGINT | |
UInt64 | BIGINT | |
Float32 | FLOAT | |
Float64 | DOUBLE PRECISION | |
Decimal(P, S) | DECIMAL | |
Decimal32(S) | DECIMAL | |
Decimal64(S) | DECIMAL | |
Decimal128(S) | DECIMAL | |
布爾 | 無,使用UInt8代替。 | BOOLEAN |
字符 | String | TEXT |
FixString(N) | 無,使用TEXT代替。 | |
LowCardinality | 無,自動智能設定或使用 | |
二進制 | 無,使用String或FixString(N)。 | BIT(n)、VARBIT(n)、BYTEA、CHAR(n) 等數(shù)據(jù)類型。 |
其他 | UUID | UUID |
Enum | 不支持,使用TEXT代替。 | |
Nested、 Tuple、Array | 數(shù)組 |
元數(shù)據(jù)遷移
元數(shù)據(jù)的遷移,主要指進行建表DDL的遷移。
在ClickHouse-Client使用如下命令語句查看源ClickHouse實例的數(shù)據(jù)庫列表。
說明查詢到的表中system是系統(tǒng)數(shù)據(jù)庫,不需要遷移,可以直接過濾掉。
clickhouse-client --host="<host>" --port="<port>" --user="<username>" --password="<password>" --query="SHOW databases" > database.list;
參數(shù)說明如下。
參數(shù)
說明
host
ClickHouse源實例的地址。
port
ClickHouse源實例的端口。
username
登錄ClickHouse源實例的賬號,擁有DML讀寫和設置權(quán)限,允許DDL權(quán)限。
password
登錄ClickHouse源實例賬號的密碼。
在ClickHouse-Client使用如下命令語句查看源ClickHouse實例的數(shù)據(jù)表列表。
說明查詢到的表中,如果有以.inner.開頭的表,此類表是物化視圖的內(nèi)部表,不需要遷移,可以直接過濾掉。
clickhouse-client --host="<host>" --port="<port>" --user="<username>" --password="<password>" --query="SHOW tables from <database_name>" > table.list;
參數(shù)說明如下。
參數(shù)
說明
host
源ClickHouse實例的地址。
port
源ClickHouse實例的端口。
username
登錄源ClickHouse實例的賬號,擁有DML讀寫和設置權(quán)限,允許DDL權(quán)限。
password
登錄源ClickHouse實例賬號的密碼。
database_name
源ClickHouse實例遷移表所在的數(shù)據(jù)庫名稱。
您也可以通過以下命令語句查詢源ClickHouse實例所有的數(shù)據(jù)庫和表名稱。
select distinct database, name from system.tables where database != 'system';
在ClickHouse-Client使用如下命令語句導出ClickHouse源實例的建表DDL。
clickhouse-client --host="<host>" --port="<port>" --user="<username>" --password="<password>" --query="SHOW CREATE TABLE <database_name>.<table_name>" > table.sql;
您也可以使用如下命令直接查看system.tables元數(shù)據(jù)表。
SELECT * FROM system.tables where database = '<database_name>' and engine != 'Distributed';
system.tables中字段的轉(zhuǎn)換說明如下。
字段
說明
database
ClickHouse的database映射到Hologres(PostgreSQL語法)的Schema概念,即ClickHouse的
create database "<database_name>";
命令映射為Hologres的create schema "<schema_name>";
命令。name
表名稱,無需改動。
engine
Hologres沒有Distributed表概念,沒有Local和Distributed之分,就是一個單表,分布式存儲和查詢,所以需要過濾掉
engine='Distributed'
的表。is_temporary
Temporary表邏輯上無須遷移,同時Hologres暫不支持Temporary表。
data_paths
metadata_path
metadata_modification_time
可忽略。
dependencies_database
dependencies_table
常見于View、Materialized View。具有dependencies的View,在Hologres中,需要先于base表創(chuàng)建。Hologres的Materialized View還未支持。
create_table_query
ClickHouse源實例表的DDL,需轉(zhuǎn)換成Hologres DDL(PostgreSQL語法)。
engine_full
Engine詳細信息,可忽略。
partition_key
對應Hologres的分區(qū)列,ClickHouse的源實例partition_key如果為col1,則Hologres建表語句后添加
partition by list (col1);
語句。sorting_key
對應Hologres的Segment Key和Clustering Key索引。
primary_key
主鍵,對應Hologres DDL語法的Primary Key。
sampling_key
Hologres DDL不支持采樣。
storage_policy
存儲策略,可忽略。
將源ClickHouse實例的建表DDL轉(zhuǎn)換為Hologres的語法(兼容PostgreSQL SQL標準)。
根據(jù)system.tables中字段的轉(zhuǎn)換說明和數(shù)據(jù)類型映射進行DDL轉(zhuǎn)換,示例如下。
將名稱為lineitem表在ClickHouse實例中的DDL轉(zhuǎn)換為Hologres的建表DDL。
ClickHouse實例的建表DDL如下所示。
-- lineitem on ClickHouse CREATE TABLE lineitem_local ON CLUSTER default( l_orderkey UInt64, l_partkey UInt32, l_suppkey UInt32, l_linenumber UInt32, l_quantity decimal(15,2), l_extendedprice decimal(15,2), l_discount decimal(15,2), l_tax decimal(15,2), l_returnflag LowCardinality(String), l_linestatus LowCardinality(String), l_shipdate Date, l_commitdate Date, l_receiptdate Date, l_shipinstruct LowCardinality(String), l_shipmode LowCardinality(String), l_comment LowCardinality(String) ) ENGINE = MergeTree PARTITION BY toYear(l_shipdate) ORDER BY (l_orderkey, l_linenumber); CREATE TABLE lineitem on cluster default as lineitem_local ENGINE = Distributed(default, default, lineitem_local, l_orderkey);
轉(zhuǎn)換后Hologres實例的建表DDL如下所示。
-- lineitem on Hologres -- create a table group with 32 shards CALL hg_create_table_group ('lineitem_tg', 32); BEGIN; CREATE TABLE LINEITEM ( L_ORDERKEY BIGINT NOT NULL, L_PARTKEY INT NOT NULL, L_SUPPKEY INT NOT NULL, L_LINENUMBER INT NOT NULL, L_QUANTITY DECIMAL(15,2) NOT NULL, L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, L_DISCOUNT DECIMAL(15,2) NOT NULL, L_TAX DECIMAL(15,2) NOT NULL, L_RETURNFLAG TEXT NOT NULL, L_LINESTATUS TEXT NOT NULL, L_SHIPDATE TIMESTAMPTZ NOT NULL, L_COMMITDATE TIMESTAMPTZ NOT NULL, L_RECEIPTDATE TIMESTAMPTZ NOT NULL, L_SHIPINSTRUCT TEXT NOT NULL, L_SHIPMODE TEXT NOT NULL, L_COMMENT TEXT NOT NULL, PRIMARY KEY (L_ORDERKEY,L_LINENUMBER) ); CALL set_table_property('LINEITEM', 'clustering_key', 'L_SHIPDATE,L_ORDERKEY'); CALL set_table_property('LINEITEM', 'segment_key', 'L_SHIPDATE'); CALL set_table_property('LINEITEM', 'table_group', 'lineitem_tg'); CALL set_table_property('LINEITEM', 'distribution_key', 'L_ORDERKEY'); -- columns with LowCardinality CALL set_table_property('LINEITEM', 'bitmap_columns', 'L_RETURNFLAG,L_LINESTATUS,L_SHIPINSTRUCT,L_SHIPMODE,L_COMMENT'); -- columns with LowCardinality CALL set_table_property('LINEITEM', 'dictionary_encoding_columns', 'L_RETURNFLAG,L_LINESTATUS,L_SHIPINSTRUCT,L_SHIPMODE,L_COMMENT'); CALL set_table_property('LINEITEM', 'time_to_live_in_seconds', '31536000'); COMMIT;
將名稱為customer表在ClickHouse實例中的DDL轉(zhuǎn)換為Hologres的建表DDL。
ClickHouse實例的建表DDL如下所示。
-- customer on ClickHouse CREATE TABLE customer_local ON CLUSTER default( c_custkey UInt32, c_name String, c_address String, c_nationkey UInt32, c_phone LowCardinality(String), c_acctbal decimal(15,2), c_mktsegment LowCardinality(String), c_comment LowCardinality(String) ) ENGINE = MergeTree ORDER BY (c_custkey); CREATE TABLE customer on cluster default as customer_local ENGINE = Distributed(default, default, customer_local, c_custkey);
轉(zhuǎn)換后Hologres實例的建表DDL如下所示。
-- customer on Hologres BEGIN; CREATE TABLE CUSTOMER ( C_CUSTKEY INT NOT NULL PRIMARY KEY, C_NAME TEXT NOT NULL, C_ADDRESS TEXT NOT NULL, C_NATIONKEY INT NOT NULL, C_PHONE TEXT NOT NULL, C_ACCTBAL DECIMAL(15,2) NOT NULL, C_MKTSEGMENT TEXT NOT NULL, C_COMMENT TEXT NOT NULL ); CALL set_table_property('CUSTOMER', 'distribution_key', 'C_CUSTKEY'); CALL set_table_property('CUSTOMER', 'table_group', 'lineitem_tg'); CALL set_table_property('CUSTOMER', 'bitmap_columns', 'C_CUSTKEY,C_NATIONKEY,C_NAME,C_ADDRESS,C_PHONE,C_MKTSEGMENT,C_COMMENT'); CALL set_table_property('CUSTOMER', 'dictionary_encoding_columns', 'C_NAME,C_ADDRESS,C_PHONE,C_MKTSEGMENT,C_COMMENT'); CALL set_table_property('CUSTOMER', 'time_to_live_in_seconds', '31536000'); COMMIT;
在PSQL客戶端使用如下命令語句將轉(zhuǎn)換后的建表DDL導入到目標Hologres實例中。
PGUSER="<username>" PGPASSWORD="<password>" psql -h "<host>" -p "<port>" -d "<database_name>" -f table.sql;
數(shù)據(jù)遷移
從源ClickHouse遷移數(shù)據(jù)至Hologres有如下三種方法。
(推薦)在源實例將數(shù)據(jù)導出為文件,然后通過
COPY語句
命令語句(JDBC/PSQL)將文件導入到Hologres目標實例。通過編寫Flink、Spark job將源實例數(shù)據(jù)讀出,然后寫入目標Hologres實例,請參見使用Spark導入。
通過DataWorks數(shù)據(jù)集成或DataX,讀取源實例數(shù)據(jù),后寫入目標Hologres實例,請參見數(shù)據(jù)集成概述。
在源實例將數(shù)據(jù)導出為文件,再導入目標Hologres實例,操作步驟如下。
在ClickHouse-Client使用如下命令語句導出源實例數(shù)據(jù)至本地CSV文件。
clickhouse-client --host="<host>" --port="<port>" --user="<username>" --password="<password>" --query="select * from <database_name>.<table_name> FORMAT CSV" > table.csv;
參數(shù)說明如下。
參數(shù)
說明
host
ClickHouse源實例的地址。
port
ClickHouse源實例的端口。
username
登錄ClickHouse源實例的賬號,擁有DML讀寫和設置權(quán)限,允許DDL權(quán)限。
password
登錄ClickHouse源實例賬號的密碼。
database_name
ClickHouse源實例遷移表所在的數(shù)據(jù)庫名稱。
table_name
ClickHouse源實例遷移的表名稱。
在PSQL客戶端使用如下命令語句將本地CSV文件導入到Hologres實例。
PGUSER="<username>" PGPASSWORD="<password>" psql -h "<host>" -p "<port>" -d "<database_name>" -c "COPY <schema_name>.<table_name> FROM STDIN (FORMAT 'csv')" < table.csv;
參數(shù)說明如下。
參數(shù)
說明
username
登錄Hologres目標實例的賬號,擁有DML讀寫和設置權(quán)限,允許DDL權(quán)限。通常是阿里云賬號的AccessKey ID,您可以單擊AccessKey 管理,獲取AccessKey ID。
password
登錄Hologres目標實例賬號的密碼,通常是阿里云賬號的AccessKey Secret,您可以單擊AccessKey 管理,獲取AccessKey Secret。
host
Hologres實例的服務器地址。
您可以登錄管理控制臺,進入實例詳情頁,從網(wǎng)絡信息獲取。
port
Hologres實例的端口。
您可以登錄管理控制臺,進入實例詳情頁,從網(wǎng)絡信息獲取。
database_name
遷移到Hologres實例的數(shù)據(jù)庫名稱。
schema_name
遷移到Hologres實例的Schema名稱,不填默認為public。
table_name
遷移到Hologres實例的表名稱。
在Hologres中查詢導入數(shù)據(jù),驗證數(shù)據(jù)是否導入成功。
ClickHouse離線整庫同步
可以通過DataWorks數(shù)據(jù)集成同步解決方案將ClickHouse整個數(shù)據(jù)庫的數(shù)據(jù)離線同步至Hologres,詳情請參見ClickHouse整庫數(shù)據(jù)離線同步至Hologres。
數(shù)據(jù)查詢語句遷移
Hologres的數(shù)據(jù)查詢語句采用PostgreSQL語法,ClickHouse為自創(chuàng)語法,部分兼容SQL ANSI,兩者語法基本類似,但有細節(jié)上的差異。所以需要對數(shù)據(jù)查詢語句進行遷移,常見的是SQL中使用函數(shù)名的遷移,例如Scalar函數(shù)、Window函數(shù)等。
ClickHouse和Hologres的SQL有如下差別。
ClickHouse中用
''
包圍的列名,在Hologres中需要替換成""
包圍。ClickHouse中使用
SELECT X FROM <database_name>.<table_name>
命令,在Hologres中使用SELECT X FROM <schema_name>.<table_name>
命令。表達式差異,主要表現(xiàn)在函數(shù)上,函數(shù)映射表(僅列出有差異的函數(shù),未列出則無差異)如下所示。
ClickHouse
Hologres
toYear(expr)
to_char(expr, 'YYYY')
toInt32(expr)
CAST(expr as INTEGER)
uniq()
uniqCombined()
uniqCombined64()
uniqHLL12()
approx_count_distinct()
uniqExact()
count(distinct x)
quantile(level) (expr)
approx_percentile(level) WITHIN GROUP(ORDER BY expr)
quantileExact(level) (expr)
percentile_cont (level) WITHIN GROUP(ORDER BY expr)
數(shù)據(jù)查詢語句遷移有如下方法。
正則替換
采用正則替換的方式,將ClickHouse的一些固定模式的語法(函數(shù)名、標志符、表達式等)轉(zhuǎn)換成Hologres的語法,例如將
''
轉(zhuǎn)換為""
。ClickHouse Extension
Hologres中具備ClickHouse Extension,兼容部分ClickHouse函數(shù),無需轉(zhuǎn)換,例如
toUInt32()
函數(shù)。
下面以部分TPC-H Query為例,將ClickHouse源實例的數(shù)據(jù)查詢語句遷移至Hologres的示例如下所示。
示例一。
在ClickHouse實例上的數(shù)據(jù)查詢語句。
-- Q1 on ClickHouse select l_returnflag, l_linestatus, sum(l_quantity) as sum_qty, sum(l_extendedprice) as sum_base_price, sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, avg(l_quantity) as avg_qty, avg(l_extendedprice) as avg_price, avg(l_discount) as avg_disc, count(*) as count_order from lineitem where l_shipdate <= date '1998-12-01' - interval '90' day group by l_returnflag, l_linestatus order by l_returnflag, l_linestatus;
轉(zhuǎn)換后Hologres實例的數(shù)據(jù)查詢語句。
-- Q1 on Hologres select l_returnflag, l_linestatus, sum(l_quantity) as sum_qty, sum(l_extendedprice) as sum_base_price, sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, avg(l_quantity) as avg_qty, avg(l_extendedprice) as avg_price, avg(l_discount) as avg_disc, count(*) as count_order from lineitem where l_shipdate <= date '1998-12-01' - interval '90' day group by l_returnflag, l_linestatus order by l_returnflag, l_linestatus;
示例二。
在ClickHouse實例上的數(shù)據(jù)查詢語句。
-- Q4 on ClickHouse select o_orderpriority, count(*) as order_count from orders where o_orderdate >= date '1993-07-01' and o_orderdate < date '1993-07-01' + interval '3' month and o_orderdate in ( select o_orderdate from lineitem, orders where l_orderkey = o_orderkey and l_commitdate < l_receiptdate ) group by o_orderpriority order by o_orderpriority;
轉(zhuǎn)換后Hologres實例的數(shù)據(jù)查詢語句。
-- Q4 on Hologres select o_orderpriority, count(*) as order_count from orders where o_orderdate >= date '1993-07-01' and o_orderdate < date '1993-07-01' + interval '3' month and exists ( select * from lineitem where l_orderkey = o_orderkey and l_commitdate < l_receiptdate ) group by o_orderpriority order by o_orderpriority;
示例三。
在ClickHouse實例上的數(shù)據(jù)查詢語句。
-- Q11 on ClickHouse select ps_partkey, sum(ps_supplycost * ps_availqty) as value from partsupp, supplier, nation where ps_suppkey = s_suppkey and s_nationkey = n_nationkey and n_name = 'GERMANY' group by ps_partkey having sum(ps_supplycost * ps_availqty) > ( select sum(ps_supplycost * ps_availqty) * toDecimal32(0.0000010000,9) from partsupp, supplier, nation where ps_suppkey = s_suppkey and s_nationkey = n_nationkey and n_name = 'GERMANY' ) order by value desc limit 100;
轉(zhuǎn)換后Hologres實例的數(shù)據(jù)查詢語句。
-- Q11 on Hologres select ps_partkey, sum(ps_supplycost * ps_availqty) as value from partsupp, supplier, nation where ps_suppkey = s_suppkey and s_nationkey = n_nationkey and n_name = 'GERMANY' group by ps_partkey having sum(ps_supplycost * ps_availqty) > ( select sum(ps_supplycost * ps_availqty) * 0.0000010000 from partsupp, supplier, nation where ps_suppkey = s_suppkey and s_nationkey = n_nationkey and n_name = 'GERMANY' ) order by value desc limit 100;
函數(shù)兼容
Hologres與Clickhouse存在大量語法一致的基礎(chǔ)函數(shù)。針對其他Clickhouse函數(shù),Hologres支持部分函數(shù)或其同語義函數(shù)。具體函數(shù)兼容情況請參見Clickhouse兼容函數(shù)。