当前位置: 首页 > news >正文

Apache Doris 实战教程:手把手实现 ClickHouse 表结构迁移与数据校验

阅读前提

本教程假设你已具备:

  • 基本的 ClickHouse 使用经验(了解 MergeTree、分布式表概念)
  • 已部署 Apache Doris 集群(单节点或集群均可)
  • 会使用基本的 SQL 和 Shell 命令

第一步:环境准备 & 连接 Doris

首先确认 Doris 集群可连接,并创建目标 Database:

-- 连接 Doris(默认 MySQL 协议,端口 9030) -- mysql -h 127.0.0.1 -P 9030 -u root -- 创建目标数据库 CREATE DATABASE IF NOT EXISTS migration_demo; -- 查看集群状态 SHOW BACKENDS; SHOW FRONTENDS;

第二步:DDL 自动转换——从 CK 到 Doris

2.1 核心映射规则

ClickHouse 和 Apache Doris 在数据类型、表引擎、分区策略上存在差异,需要做以下映射:

# ck_to_doris_ddl.py —— DDL 类型映射核心代码 # ClickHouse → Doris 类型的映射表(覆盖快手支持的 22 种) TYPE_MAP = { "UInt8": "TINYINT", "UInt16": "SMALLINT", "UInt32": "INT", "UInt64": "BIGINT", "Int8": "TINYINT", "Int16": "SMALLINT", "Int32": "INT", "Int64": "BIGINT", "Float32": "FLOAT", "Float64": "DOUBLE", "String": "VARCHAR(65533)", "FixedString": "CHAR", "Date": "DATE", "DateTime": "DATETIME", "DateTime64": "DATETIME", "Array": "ARRAY", "Map": "MAP", "LowCardinality": "VARCHAR", # LowCardinality 展开为 VARCHAR "Enum8": "TINYINT", # Enum 通常转为基础类型 "Enum16": "SMALLINT", } def convert_type(ck_type): """转换 ClickHouse 类型到 Doris 类型""" # 处理 Nullable(Type) if ck_type.startswith("Nullable("): inner = ck_type[9:-1] return convert_type(inner) # Doris 默认支持 NULL,去除 Nullable 包装 # 处理 Array(Type) if ck_type.startswith("Array("): inner = ck_type[6:-1] return f"ARRAY<{convert_type(inner)}>" # 基本类型映射 return TYPE_MAP.get(ck_type, "VARCHAR(65533)") # 未知类型兜底为 VARCHAR

2.2 生成完整的 Doris DDL

# 接上文件 ck_to_doris_ddl.py import re def generate_doris_ddl(ck_table_name, ck_columns, ck_partition_by, ck_order_by): """ 根据 ClickHouse 表信息生成 Doris DDL 参数: ck_table_name: ClickHouse 表名 ck_columns: [(col_name, col_type), ...] ck_partition_by: ClickHouse 分区表达式 ck_order_by: ClickHouse 排序键列名列表 """ doris_table = ck_table_name.replace(".", "_") # 1. 生成列定义 col_defs = [] for col_name, col_type in ck_columns: doris_type = convert_type(col_type) col_defs.append(f" {col_name} {doris_type}") # 2. 从 ORDER BY 推导 DUPLICATE KEY(前两列作为 Key) key_cols = ck_order_by[:2] if len(ck_order_by) >= 2 else ck_order_by # 3. 分区策略:取第一个 Date/DateTime 列做 RANGE 分区 partition_col = ck_partition_by if ck_partition_by else "event_date" # 4. 分桶:按第一列 HASH,默认 32 桶 bucket_col = ck_order_by[0] if ck_order_by else ck_columns[0][0] bucket_num = 32 # 可根据分区数据量调整 ddl = f""" CREATE TABLE IF NOT EXISTS {doris_table} ( {','.join(col_defs)} ) ENGINE = OLAP DUPLICATE KEY({','.join(key_cols)}) PARTITION BY RANGE({partition_col}) () DISTRIBUTED BY HASH({bucket_col}) BUCKETS {bucket_num} PROPERTIES ( "replication_num" = "3" ); """ return ddl.strip() # ---------- 使用示例 ---------- if __name__ == "__main__": # 模拟一个 ClickHouse 表结构 ck_columns = [ ("event_date", "Date"), ("user_id", "UInt64"), ("event_type", "String"), ("event_value", "Float64"), ("event_time", "DateTime"), ("tags", "Array(String)"), ("ext_info", "Map(String, String)"), ] ck_order_by = ["user_id", "event_time"] ddl = generate_doris_ddl( ck_table_name="db.ck_user_behavior", ck_columns=ck_columns, ck_partition_by="event_date", ck_order_by=ck_order_by ) print("-- 生成的 Doris DDL --") print(ddl)

执行结果将生成类似以下 DDL:

-- 生成的 Doris DDL -- CREATE TABLE IF NOT EXISTS db_ck_user_behavior ( event_date DATE, user_id BIGINT, event_type VARCHAR(65533), event_value DOUBLE, event_time DATETIME, tags ARRAY<VARCHAR(65533)>, ext_info MAP<VARCHAR(65533),VARCHAR(65533)> ) ENGINE = OLAP DUPLICATE KEY(user_id, event_time) PARTITION BY RANGE(event_date) () DISTRIBUTED BY HASH(user_id) BUCKETS 32 PROPERTIES ( "replication_num" = "3" );

第三步:配置双跑——数据同时写入 CK 和 Doris

迁移期间,新增数据需要同时写入 ClickHouse 和 Apache Doris:

#!/bin/bash # dual_write.sh —— 离线数据双写脚本 DORIS_HOST="127.0.0.1" DORIS_PORT="8030" # Stream Load HTTP 端口 DORIS_USER="root" DORIS_DB="migration_demo" DORIS_TABLE="user_behavior" # 假设已有 Hive → CK 的导出文件 data_export.csv DATA_FILE="/data/export/data_export.csv" # Stream Load 写入 Doris curl --location-trusted -u ${DORIS_USER}: \ -H "label:dual_write_$(date +%s)" \ -H "column_separator:," \ -H "format:csv" \ -T ${DATA_FILE} \ http://${DORIS_HOST}:${DORIS_PORT}/api/${DORIS_DB}/${DORIS_TABLE}/_stream_load echo "Dual write completed: $(date)"

第四步:存量数据迁移——Hive 到 Doris

对于上游 Hive 数据完整的情况,直接复用已有 ETL 链路:

-- 通过 Doris Multi-Catalog 直接查询 Hive 并 INSERT INTO 目标表 -- 适用于 Hive 数据保留周期够长的场景 -- 1. 创建 Hive Catalog CREATE CATALOG hive_catalog PROPERTIES ( "type" = "hms", "hive.metastore.uris" = "thrift://hive-metastore:9083" ); -- 2. 将 Hive 数据批量写入 Doris 内表 INSERT INTO migration_demo.user_behavior SELECT event_date, user_id, event_type, event_value, event_time FROM hive_catalog.ods.user_behavior_hive WHERE event_date >= '2025-01-01'; -- 3. 查看导入状态 SHOW LOAD FROM migration_demo;

第五步:数据校验——确保迁移结果可靠

5.1 基础数据量校验

-- 第一层校验:行数和基础统计 -- 在 Doris 中执行 SELECT 'Doris' AS source, COUNT(*) AS row_count, SUM(event_value) AS total_value, COUNT(DISTINCT user_id) AS unique_users FROM migration_demo.user_behavior UNION ALL -- 对比 ClickHouse(需单独查询后贴入) -- 预期结果:row_count 和 total_value 应一致 SELECT 'ClickHouse' AS source, 1000000, 12345678.90, 50000;

5.2 维度聚合校验

-- 第二层:按核心维度 GROUP BY 对比 SELECT event_date, event_type, COUNT(*) AS cnt, SUM(event_value) AS sum_val, AVG(event_value) AS avg_val FROM migration_demo.user_behavior WHERE event_date >= '2025-06-01' GROUP BY event_date, event_type ORDER BY event_date, event_type LIMIT 100; -- 将此结果与 ClickHouse 中相同查询结果逐行对比

5.3 Float 精度校验

# float_check.py —— 精度容忍校验 import math def check_float_precision(ck_value, doris_value, tolerance=0.001): """ 检查 Float 类型精度偏差 参数: ck_value: ClickHouse 侧数值 doris_value: Doris 侧数值 tolerance: 相对容忍阈值(默认 0.1%) """ if ck_value == 0 and doris_value == 0: return True relative_error = abs(ck_value - doris_value) / max(abs(ck_value), abs(doris_value)) if relative_error > tolerance: print(f"⚠ 精度超标: CK={ck_value}, Doris={doris_value}, error={relative_error:.6f}") return False return True # 使用示例 assert check_float_precision(3.14159265, 3.14159) # True(偏差约 0.00008%) assert not check_float_precision(3.14, 3.25) # False(偏差约 3.5%,超标)

第六步:灰度切换

#!/bin/bash # gray_switch.sh —— 通过 OneSQL 或其他路由层逐步切换 # 1. 10% 流量打向 Doris echo "Gray release: 10% traffic" # onesql-cli set-route --table user_behavior --target doris --weight 10 # 2. 观察 24 小时,确认无异常 # 3. 50% 流量 echo "Gray release: 50% traffic" # onesql-cli set-route --table user_behavior --target doris --weight 50 # 4. 观察 24 小时 # 5. 100% 流量 echo "Full switch to Doris" # onesql-cli set-route --table user_behavior --target doris --weight 100

常见问题

Q:DDL 转换后查询变慢了?A:检查三点:① Bucket 数是否根据数据量合理设置(太小导致并发不足,太大增加元数据压力);② 分桶 Key 是否与查询模式匹配;③ 需要 Join 的两张表是否配置了 Colocation Group。

Q:Stream Load 导入报错 "too many open files"?A:Doris BE 进程需要调整ulimit -n,建议设为 65536 以上。

Q:补数期间 Doris 查询性能受影响?A:建议将补数任务放在业务低峰期执行,或在导入时设置"strict_mode" = "false"降低导入对查询的影响。

http://www.jsqmd.com/news/1257276/

相关文章:

  • 广州GEO优化服务怎么选?2026年企业GEO服务商靠谱选型指南与深度测评 - 科技快讯
  • 2026上海购宠终极攻略|避雷指南+深度测评+选宠干货!3000㎡CKU认证繁育基地,三区连锁零套路 - 同城大型猫犬舍
  • 新一代 Ai coding 工程进阶系列-前言
  • TLV320ADC3101 ADC数字信号处理与抽取滤波器配置实战指南
  • 共享充电宝机柜物联网卡后台不显示设备在线状态?假性离线根源解析与根治方案
  • 模型网关不是多接几家 API 当接口人——给厨房配个会比价、会兜底、会记账的采购总管
  • 无货源铺货软件怎么用?抖音小店与微信小店批量铺货流程、FAQ和抖掌柜教程 - 电商分享
  • AIGC检测工具选型陷阱大全,92%团队踩坑的4个致命误区:从BERT到LLM-Detector实战评测报告
  • 器,生成复指数信号与本振信号相乘,在ip核设置的过程中主要由三个模式 BYPASS 这个又叫直通模式,即不进行任何数字混频,基带信号 ...
  • 广州服饰品牌企业做GEO服务商怎么选?2026年五家服务商深度测评与靠谱选型指南 - 企业新闻快传
  • 大模型推理引擎vLLM(30): 参考sglang代码,重构vllm021中EP高吞吐代码,消除空泡问题:400us减小到25us
  • 广州招商加盟服务企业做GEO服务商怎么选?2026年五家机构深度对比与靠谱选型指南 - 企业新闻快传
  • 智能快递柜格口监控物联网卡在老旧小区弱网环境下多运营商切换组网方案
  • 2026北京香奈儿回收哪家口碑好?尚典CF/2.55鉴定实力过硬,这份本地测评榜单给出答案 - 奢品流通笔谈
  • Unity集成Gaussian Splatting:5分钟实现实时三维点云渲染
  • templates/ 是 Helm Chart 的核心引擎室
  • 天道观后感2
  • 深圳购宠终极测评|避雷+攻略+深度评分三合一!3000㎡CKU认证繁育基地,五区连锁零套路 - 同城大型猫犬舍
  • GanttProject完全指南:免费开源项目管理工具的5大核心功能详解
  • 高性能ADC评估实战:从ADS7851EVM-PDK套件解析数据采集系统设计
  • 5分钟解锁九大网盘真实下载链接:LinkSwift完全指南
  • 计算机基础·计算机组成原理
  • Excel行高调整全攻略:从基础操作到批量处理技巧
  • Stage 0: Understand What An Agent Is - Charlie
  • Helm 部署 K8s 集群完整笔记
  • 2026 年 7 月新发布:兰州口碑好的膜结构自行车棚优质厂家有哪些,不再租棚?膜结构自行车棚如何颠覆你的露营体验 - 行业鉴选官
  • windows网络适配器驱动开发-开发 WiFiCx 客户端驱动程序(三)
  • 广州家居建材材料服务企业做GEO服务商怎么选?2026年五家服务商深度测评与靠谱选型指南 - 小随科技
  • 手把手教你用ChatGPT+Runway+CapCut搭建个人AI短视频工厂:1人日均产出27条优质内容(含自动化发布SOP)
  • 2026北京名包回收哪家口碑好?尚典爱马仕/香奈儿鉴定实力过硬,这份本地测评榜单给出答案 - 奢品流通笔谈