本文為您介紹如何遷移自建ClickHouse的資料庫表和資料至即時數倉Hologres上進行資料開發。
前提條件
開通Hologres,詳情請參見購買Hologres。
已有ClickHouse執行個體,並且安裝ClickHouse-Client工具,如需安裝請單擊ClickHouse-Client,安裝和使用詳情請參見Getting Started。
使用PSQL用戶端串連Hologres執行個體,詳情請參見PSQL用戶端。
背景資訊
ClickHouse是一個用於聯機分析(OLAP)的列式資料庫管理系統。Hologres是阿里巴巴自主研發的一款互動式分析產品,支援亞秒級響應與高QPS,您可以從ClickHouse遷移表和資料至Hologres擷取更好的資料開發體驗。
Hologres與ClickHouse產品特性對比如下。
分類 | 對比項 | Clickhouse | Hologres |
產品 | 定位 | 流量分析 | 通用即時數倉:資料分析和線上服務。 |
寫入 | 儲存 | 列存 | 列存和行存。 |
寫入可見度 | 秒級(需要用戶端攢資料進行批處理,分布式表寫入依賴Shard資料複製完成) | 毫秒級(寫入自適應批處理,寫入即可查) | |
寫入效能 | 高 | 非常高 | |
明細儲存 | 支援 | 支援 | |
主鍵(Primary Key) | 非資料庫主鍵(不支援唯一性限制式,僅用於索引+彙總) | 標準資料庫主鍵,支援唯一性限制式。 | |
可更新 | 不完備,能力弱(不支援基於主鍵的高QPS更新)。 | 完整支援(支援基於主鍵的高QPS更新)。 | |
即時寫入 | Append |
| |
索引 |
|
說明 自動建有minmax、bloom filter、ngram等索引,對使用者透明。 | |
查詢 | 最佳化器 | RBO(Rule-Based Optimizer) | CBO(Cost-Based Optimizer) |
聯邦查詢 | 支援(Engine支援HDFS、Kafka) | 支援(FDW直讀MaxCompute、Hive) | |
預彙總 | 支援(通過MergeTree) | 支援(預存程序+定期調度) | |
高QPS點查 | 不支援 | 支援,QPS可達千萬以上。 | |
單表複雜查詢 | 效能好 | 效能好 | |
多表JOIN | 效能差 | 效能好 | |
SQL文法 | 自訂文法 | 相容PostgreSQL,功能更豐富。 | |
WINDOW FUNCTION | 不支援 | 支援 | |
事務 | 事務ACID | 無(不保證寫入即可查,最終一致性) | 有限支援(支援DDL事務、單行事務、基於snapshot的可見度) |
複製 | 容災和備份 | 通過Replication實現(遠程ZK+CK) | 通過Binlog複製實現邏輯複製,通過底層機制實現物理複製。 |
進階功能 | Binlog | 無 | 提供Binlog |
向量檢索 | ClickHouse 22.8及以上版本支援 | 支援 | |
空間資料 | 不支援 | 支援 | |
安全管理 | 自訂許可權 | 相容PG許可權模型、豐富的許可權控制、IP白名單、資料脫敏。 | |
儲存計算分離 | 不分離,單機容量限制 | 分離,儲存容量近乎無限。 | |
可用性 | 使用者手工處理Failover | Failover自動回復 | |
營運 | 複雜(手工維護Shard分布) | 免營運 | |
生態 | 資料接入 | Kafka、Flink、Spark、... | Flink、Spark、JDBC、DataX、… |
BI工具 | 支援對接少量BI工具(Tableau、Superset、...) | 相容PostgreSQL生態,支援對接100+主流BI工具。 |
資料類型映射
ClickHouse與Hologres的資料類型映射如下表所示。
類別 | ClickHouse | Hologres |
日期 | Date | Date |
DateTime | TIMESTAMPTZ | |
DateTime(timezone) | TIMESTAMPTZ | |
DateTime64 | TIMESTAMPTZ | |
數值 | Int8 | 不支援單位元組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) 等資料類型。 |
其他 | UUID | UUID |
Enum | 不支援,使用TEXT代替。 | |
Nested、 Tuple、Array | 數組 |
中繼資料遷移
中繼資料的遷移,主要指進行建表DDL的遷移。
在ClickHouse-Client使用如下命令語句查看源ClickHouse執行個體的資料庫列表。
說明查詢到的表中system是系統資料庫,不需要遷移,可以直接過濾掉。
clickhouse-client --host="<host>" --port="<port>" --user="<username>" --password="<password>" --query="SHOW databases" > database.list;
參數說明如下。
參數
說明
host
ClickHouse源執行個體的地址。
port
ClickHouse源執行個體的連接埠。
username
登入ClickHouse源執行個體的帳號,擁有DML讀寫和設定許可權,允許DDL許可權。
password
登入ClickHouse源執行個體帳號的密碼。
在ClickHouse-Client使用如下命令語句查看源ClickHouse執行個體的資料表列表。
說明查詢到的表中,如果有以.inner.開頭的表,此類表是物化視圖的內部表,不需要遷移,可以直接過濾掉。
clickhouse-client --host="<host>" --port="<port>" --user="<username>" --password="<password>" --query="SHOW tables from <database_name>" > table.list;
參數說明如下。
參數
說明
host
源ClickHouse執行個體的地址。
port
源ClickHouse執行個體的連接埠。
username
登入源ClickHouse執行個體的帳號,擁有DML讀寫和設定許可權,允許DDL許可權。
password
登入源ClickHouse執行個體帳號的密碼。
database_name
源ClickHouse執行個體遷移表所在的資料庫名稱。
您也可以通過以下命令語句查詢源ClickHouse執行個體所有的資料庫和表名稱。
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中繼資料表。
SELECT * FROM system.tables where database = '<database_name>' and engine != 'Distributed';
system.tables中欄位的轉換說明如下。
欄位
說明
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表建立。Hologres的Materialized View還未支援。
create_table_query
ClickHouse源執行個體表的DDL,需轉換成Hologres DDL(PostgreSQL文法)。
engine_full
Engine詳細資料,可忽略。
partition_key
對應Hologres的分區列,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轉換為Hologres的文法(相容PostgreSQL SQL標準)。
根據system.tables中欄位的轉換說明和資料類型映射進行DDL轉換,樣本如下。
將名稱為lineitem表在ClickHouse執行個體中的DDL轉換為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);
轉換後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轉換為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);
轉換後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用戶端使用如下命令語句將轉換後的建表DDL匯入到目標Hologres執行個體中。
PGUSER="<username>" PGPASSWORD="<password>" psql -h "<host>" -p "<port>" -d "<database_name>" -f table.sql;
資料移轉
從源ClickHouse遷移資料至Hologres有如下三種方法。
(推薦)在源執行個體將資料匯出為檔案,然後通過
COPY語句
命令語句(JDBC/PSQL)將檔案匯入到Hologres目標執行個體。通過編寫Flink、Spark job將源執行個體資料讀出,然後寫入目標Hologres執行個體,請參見使用Spark匯入。
通過DataWorksData Integration或DataX,讀取源執行個體資料,後寫入目標Hologres執行個體,請參見Data Integration概述。
在源執行個體將資料匯出為檔案,再匯入目標Hologres執行個體,操作步驟如下。
在ClickHouse-Client使用如下命令語句匯出源執行個體資料至本地CSV檔案。
clickhouse-client --host="<host>" --port="<port>" --user="<username>" --password="<password>" --query="select * from <database_name>.<table_name> FORMAT CSV" > table.csv;
參數說明如下。
參數
說明
host
ClickHouse源執行個體的地址。
port
ClickHouse源執行個體的連接埠。
username
登入ClickHouse源執行個體的帳號,擁有DML讀寫和設定許可權,允許DDL許可權。
password
登入ClickHouse源執行個體帳號的密碼。
database_name
ClickHouse源執行個體遷移表所在的資料庫名稱。
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;
參數說明如下。
參數
說明
username
登入Hologres目標執行個體的帳號,擁有DML讀寫和設定許可權,允許DDL許可權。通常是阿里雲帳號的AccessKey ID,您可以單擊AccessKey 管理,擷取AccessKey ID。
password
登入Hologres目標執行個體帳號的密碼,通常是阿里雲帳號的AccessKey Secret,您可以單擊AccessKey 管理,擷取AccessKey Secret。
host
Hologres執行個體的伺服器位址。
您可以登入管理主控台,進入執行個體詳情頁,從網路資訊擷取。
port
Hologres執行個體的連接埠。
您可以登入管理主控台,進入執行個體詳情頁,從網路資訊擷取。
database_name
遷移到Hologres執行個體的資料庫名稱。
schema_name
遷移到Hologres執行個體的Schema名稱,不填預設為public。
table_name
遷移到Hologres執行個體的表名稱。
在Hologres中查詢匯入資料,驗證資料是否匯入成功。
ClickHouse離線整庫同步
可以通過DataWorksData Integration同步解決方案將ClickHouse整個資料庫的資料離線同步至Hologres,詳情請參見ClickHouse整庫資料離線同步至Hologres。
資料查詢語句遷移
Hologres的資料查詢語句採用PostgreSQL文法,ClickHouse為自創文法,部分相容SQL ANSI,兩者文法基本類似,但有細節上的差異。所以需要對資料查詢語句進行遷移,常見的是SQL中使用函數名的遷移,例如Scalar函數、Window函數等。
ClickHouse和Hologres的SQL有如下差別。
ClickHouse中用
''
包圍的列名,在Hologres中需要替換成""
包圍。ClickHouse中使用
SELECT X FROM <database_name>.<table_name>
命令,在Hologres中使用SELECT X FROM <schema_name>.<table_name>
命令。運算式差異,主要表現在函數上,函數映射表(僅列出有差異的函數,未列出則無差異)如下所示。
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)
資料查詢語句遷移有如下方法。
正則替換
採用正則替換的方式,將ClickHouse的一些固定模式的文法(函數名、標誌符、運算式等)轉換成Hologres的文法,例如將
''
轉換為""
。ClickHouse Extension
Hologres中具備ClickHouse Extension,相容部分ClickHouse函數,無需轉換,例如
toUInt32()
函數。
下面以部分TPC-H Query為例,將ClickHouse源執行個體的資料查詢語句遷移至Hologres的樣本如下所示。
樣本一。
在ClickHouse執行個體上的資料查詢語句。
-- 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;
轉換後Hologres執行個體的資料查詢語句。
-- 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執行個體上的資料查詢語句。
-- 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;
轉換後Hologres執行個體的資料查詢語句。
-- 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執行個體上的資料查詢語句。
-- 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;
轉換後Hologres執行個體的資料查詢語句。
-- 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;
函數相容
Hologres與Clickhouse存在大量文法一致的基礎函數。針對其他Clickhouse函數,Hologres支援部分函數或其同語義函數。具體函數相容情況請參見Clickhouse相容函數。