
在实际的数据仓库和实时分析场景中Apache Doris 凭借其高性能、易用性和与 Hadoop 生态的良好兼容性成为了许多团队处理海量数据的核心组件。然而从成功安装部署到真正让数据跑起来中间最关键的一步就是正确地创建数据表。很多新手在初次接触 Doris 时往往因为对表模型、分区、分桶等核心概念理解不透彻导致创建的表要么查询性能低下要么数据导入失败甚至影响集群稳定性。本文将围绕 Doris 数据表的创建从核心概念、环境准备、建表实践到常见问题排查提供一个完整、可复现的教程。无论你是刚刚完成 Doris 的单机部署还是正在使用 Doris Manager 进行集群管理都能通过本文掌握创建一张高效、稳定 Doris 数据表的核心方法。1. 理解 Doris 数据表的核心设计模型、分区与分桶在动手创建表之前必须理解 Doris 表设计的三个核心概念数据模型、分区和分桶。这直接决定了数据如何存储、查询如何加速以及数据如何管理。1.1 数据模型决定数据聚合与唯一性Doris 主要提供三种数据模型Duplicate Key、Aggregate Key 和 Unique Key。选择哪种模型取决于你的数据特性和查询需求。Duplicate Key明细模型这是最简单的模型。表的所有列都是排序键Key列数据完全按照导入顺序存储不做任何聚合。适用于需要保留原始明细日志、行为数据的场景例如用户点击流、操作日志。查询时可以基于任意列进行过滤。Aggregate Key聚合模型这是 Doris 的经典模型。它定义了 Key 列和 Value 列。Key 列相同的行在导入时会对 Value 列进行预聚合如 SUM、MAX、MIN。这极大地提升了聚合查询的性能。适用于报表类、统计类场景例如每日的销售额、用户数统计。Unique Key唯一模型可以看作是 Aggregate Key 模型的一个特例它保证了 Key 列的唯一性。对于相同 Key 的数据新导入的数据会替换旧数据REPLACE。适用于需要实时更新的维度表、用户画像表等。选择模型的根本原则是如果你的查询以聚合为主选 Aggregate如果需要精确的明细记录选 Duplicate如果需要主键唯一并更新选 Unique。1.2 分区与分桶两级数据划分理解了数据如何组织模型接下来要理解数据如何分布分区与分桶。这是 Doris 实现并行查询和高性能的关键。分区Partition通常按时间进行范围划分例如按天、按月。分区是逻辑上的概念主要用于数据管理可以方便地删除旧分区DROP PARTITION或增加新分区。查询时通过分区裁剪可以快速跳过无关数据大幅提升查询效率。分桶Bucket在分区内数据会进一步被划分到多个分桶中。分桶是物理上的概念数据文件实际存储在分桶目录下。分桶列通常是查询中高频使用的过滤条件列如user_id,city。分桶有两个核心作用一是数据打散避免数据倾斜二是为 Join 查询提供 Colocate 优化可能。一个常见的类比是一个图书馆Doris 集群有很多书架节点。分区就像按年份2023, 2024给图书分类。分桶就像在每个年份区域里再按作者姓氏首字母A-M, N-Z把书放到不同的书架上。这样找2023年某位作者的书就会非常快。2. 环境准备与基础操作在开始建表前确保你有一个可用的 Doris 环境。无论是通过官方文档进行单机部署还是使用 Doris Manager 图形化工具管理的集群都需要连接到 Doris 的 MySQL 协议端口进行 SQL 操作。2.1 连接 Doris 集群假设你的 Doris FE前端节点 IP 是192.168.1.100查询端口是9030默认用户是root密码为空。# 使用 MySQL 客户端连接 mysql -h 192.168.1.100 -P 9030 -u root # 或者使用支持 MySQL 协议的图形化工具如 DBeaver, Navicat连接连接成功后你会看到MySQL [(none)]提示符。2.2 创建数据库在 Doris 中表必须属于某个数据库。通常我们会为不同的业务或项目创建独立的数据库。-- 创建一个名为 demo 的数据库并指定初始副本数默认是3单机测试可设为1 CREATE DATABASE IF NOT EXISTS demo PROPERTIES (replication_num 1); -- 切换到该数据库 USE demo;注意单机部署时务必设置replication_num 1否则会因为副本无法分配到不同节点而建表失败。生产集群通常设置为3以保证数据高可用。3. 从零创建一张完整的 Doris 数据表我们将创建一个模拟的电商订单明细表使用 Duplicate 模型并按天分区、按用户ID分桶。3.1 设计表结构假设表需求如下表名order_detail记录用户订单的每一件商品。查询模式常按order_date订单日期和user_id用户ID过滤。数据量每天新增百万级需要定期清理旧数据。字段order_id订单号BIGINTuser_id用户IDINTproduct_id商品IDINTquantity购买数量INTprice单价DECIMAL(10,2)order_date订单日期DATEcity收货城市VARCHAR(20)create_time创建时间DATETIME3.2 编写建表语句根据上述需求我们选择 Duplicate 模型保留所有明细按order_date进行 RANGE 分区方便管理按user_id作为分桶列高频过滤。CREATE TABLE IF NOT EXISTS order_detail ( order_id BIGINT NOT NULL COMMENT “订单ID”, user_id INT NOT NULL COMMENT “用户ID”, product_id INT NOT NULL COMMENT “商品ID”, quantity INT NOT NULL DEFAULT “1” COMMENT “购买数量”, price DECIMAL(10, 2) NOT NULL COMMENT “商品单价”, order_date DATE NOT NULL COMMENT “订单日期”, city VARCHAR(20) COMMENT “收货城市”, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT “创建时间” ) ENGINEolap DUPLICATE KEY(order_id, user_id, product_id, order_date) -- 指定Duplicate Key列 COMMENT “订单明细表” PARTITION BY RANGE(order_date) -- 按订单日期进行范围分区 ( PARTITION p202401 VALUES LESS THAN (“2024-02-01”), -- 2024年1月数据 PARTITION p202402 VALUES LESS THAN (“2024-03-01”), -- 2024年2月数据 PARTITION p202403 VALUES LESS THAN (“2024-04-01”) -- 2024年3月数据 ) DISTRIBUTED BY HASH(user_id) BUCKETS 10 -- 按user_id哈希分桶分成10个桶 PROPERTIES ( “replication_num” “1”, -- 副本数单机设为1 “storage_medium” “SSD”, -- 存储介质SSD性能更好 “storage_cooldown_time” “9999-12-31 23:59:59” -- 冷却时间可设置数据自动从SSD迁移到HDD );执行上述 SQL如果返回Query OK则表创建成功。3.3 关键参数与子句详解DUPLICATE KEY(...): 指定了 Duplicate 模型的排序列。虽然数据不聚合但 Doris 会依据这些列对数据进行排序存储这对范围查询和点查询性能有优化作用。通常将高频过滤的列放在前面。PARTITION BY RANGE(...): 定义了分区规则。LESS THAN指定了每个分区的上界不包含。分区名如p202401建议有规律便于管理。DISTRIBUTED BY HASH(...) BUCKETS ...: 这是分桶子句。HASH(user_id)表示根据user_id的哈希值将数据分布到各个桶中。BUCKETS 10表示分10个桶。桶的数量一旦设置后期修改非常麻烦需要重新建表导数据因此初期设计需谨慎。PROPERTIES:replication_num: 数据副本数关乎数据可靠性和查询可用性。storage_medium和storage_cooldown_time: 用于冷热数据分层热数据存 SSD冷数据可自动转存 HDD 以节约成本。4. 表创建后的验证、数据导入与查询4.1 验证表结构使用DESC命令查看表结构确保与预期一致。DESC order_detail;4.2 动态管理分区上述建表语句只创建了到2024年3月的分区。对于持续增长的数据我们需要动态添加分区。Doris 也支持动态分区特性但这里演示手动添加。-- 添加2024年4月的分区 ALTER TABLE order_detail ADD PARTITION p202404 VALUES LESS THAN (“2024-05-01”); -- 查看已有分区 SHOW PARTITIONS FROM order_detail;4.3 导入测试数据Doris 支持多种数据导入方式Broker Load, Routine Load, Stream Load, Insert into。这里使用最简单的INSERT INTO插入少量测试数据。INSERT INTO order_detail (order_id, user_id, product_id, quantity, price, order_date, city) VALUES (10001, 101, 5001, 2, 29.99, ‘2024-01-15’, ‘北京’), (10002, 102, 5002, 1, 199.00, ‘2024-01-16’, ‘上海’), (10003, 101, 5003, 5, 9.90, ‘2024-02-20’, ‘北京’), (10004, 103, 5001, 1, 29.99, ‘2024-03-10’, ‘广州’);4.4 执行查询验证数据导入后执行一些查询来验证表的功能和性能。-- 1. 基础查询 SELECT * FROM order_detail WHERE order_date ‘2024-01-15’; -- 2. 聚合查询虽然模型是明细但Doris仍支持高效聚合 SELECT user_id, COUNT(*) as order_count, SUM(price * quantity) as total_amount FROM order_detail WHERE order_date ‘2024-01-01’ AND order_date ‘2024-03-01’ GROUP BY user_id; -- 3. 验证分区裁剪通过EXPLAIN查看执行计划确认是否只扫描了相关分区 EXPLAIN SELECT * FROM order_detail WHERE order_date ‘2024-02-20’;在EXPLAIN的结果中寻找partitions字段如果显示partitions1/4表示在4个分区中只扫描了1个证明分区裁剪生效。5. 建表过程中的常见问题与排查即使按照步骤操作也可能遇到各种问题。以下是几个典型问题及其排查路径。5.1 问题一建表失败报错 “Failed to create partition”现象执行建表语句时卡住一段时间后返回错误。可能原因与排查BE后端节点状态异常执行SHOW BACKENDS\G检查所有 BE 的Alive状态是否为true。磁盘空间不足登录 BE 节点检查数据存储路径在fe.conf的storage_root_path中配置的磁盘使用率。副本数设置错误单机部署却设置了“replication_num”“3”。检查建表语句或数据库属性中的replication_num单机必须为1。解决方案根据排查结果启动 BE 服务、清理磁盘或修正replication_num后重试。5.2 问题二数据导入失败报错 “Tablet writer write failed”现象使用 Stream Load 或 Broker Load 导入数据时任务失败。可能原因与排查数据格式与列定义不匹配检查源数据中每一列的数据类型、长度是否与表定义一致。例如字符串是否超长日期格式是否正确。分桶列包含NULL值如果分桶列DISTRIBUTED BY HASH的列在源数据中存在 NULL 值可能导致导入失败。确保分桶列非空或有默认值。BE 节点负载过高查看 Doris 的 Web UIFE的8030端口或监控检查 BE 的 CPU、内存和 IO 使用率。解决方案清洗源数据确保格式正确且分桶列无NULL对于负载问题可以考虑错峰导入或增加 BE 节点。5.3 问题三查询速度慢没有用到分区裁剪现象查询条件中包含了分区列但EXPLAIN显示扫描了所有分区查询很慢。可能原因与排查查询条件写法问题对分区列使用了函数或计算如WHERE YEAR(order_date) 2024这会导致 Doris 无法识别分区边界。应写为WHERE order_date ‘2024-01-01’ AND order_date ‘2025-01-01’。分区列类型不匹配表定义中order_date是DATE类型但查询时使用了字符串比较且格式不符。确保类型和格式匹配。解决方案优化查询语句确保对分区列使用直接、简单的范围或等值比较。问题现象常见原因检查命令/位置处理建议建表超时或失败BE节点宕机、磁盘满、副本数设置错误SHOW BACKENDS;,df -h, 检查建表SQL确保BE健康、磁盘充足、单机replication_num1数据导入失败列类型/格式不匹配、分桶列为NULL、BE负载高检查导入文件与表结构、SHOW PROC ‘/backends’清洗数据、修正导入语句、错峰导入查询性能差未触发分区裁剪、分桶列选择不当、无索引EXPLAIN [SQL]查看计划优化查询条件、重新评估分桶列、考虑物化视图6. 生产环境最佳实践与扩展建议在学习和测试环境跑通只是第一步要将 Doris 表用于生产还需要考虑更多。6.1 分桶数设置原则分桶数 (BUCKETS) 的设置至关重要它影响数据分布的均匀性和并行度。建议数量单个 Tablet一个分桶的一个副本的数据量建议在 100MB 到 1GB 之间。你可以根据预估分区数据量 / 建议Tablet大小来估算分桶数。例如一个分区预计有10GB数据希望每个Tablet约500MB则分桶数可设为 20。上限分桶数过多如成千上万会导致元数据膨胀管理开销大。通常建议在10到100之间。与机器数关系分桶数最好是 BE 节点数的整数倍以便数据均匀分布。6.2 使用动态分区对于按时间增长的表手动管理分区非常繁琐。强烈建议在生产环境启用动态分区。-- 在建表时或在已建表上修改属性启用动态分区 ALTER TABLE order_detail SET ( “dynamic_partition.enable” “true”, “dynamic_partition.time_unit” “DAY”, “dynamic_partition.start” “-7”, -- 保留最近7天的分区 “dynamic_partition.end” “3”, -- 提前创建未来3天的分区 “dynamic_partition.prefix” “p”, -- 分区名前缀 “dynamic_partition.buckets” “10” -- 动态创建的分区的分桶数 );这样Doris 会自动每天创建新分区并删除旧分区极大简化运维。6.3 数据模型选型再思考Aggregate 模型的局限性虽然聚合查询快但如果你需要对 Value 列进行更新UPDATE或删除DELETE或者需要查询未经聚合的明细Aggregate 模型就不合适。此时应考虑 Unique 模型或 Duplicate 模型。Unique 模型的新特性Doris 的 Unique 模型现在支持了 Merge-on-Write 实现在建表时指定“enable_unique_key_merge_on_write” “true”可以在数据导入时即完成合并大幅提升频繁更新场景下的查询性能。6.4 建表前检查清单在线上环境执行CREATE TABLE前建议对照此清单核查[ ]模型确认业务查询以聚合为主用 Aggregate。需要唯一主键更新用 Unique。其他情况用 Duplicate。[ ]分区列确认是否是时间列或可枚举的离散列是否能有效裁剪大部分查询[ ]分桶列确认是否是高频查询条件列或 Join 列是否数据分布均匀避免倾斜[ ]分桶数确认是否根据数据量估算100MB-1GB/Tablet是否为 BE 节点数的整数倍[ ]副本数确认是否与集群容量匹配生产环境通常为3[ ]字段类型确认数值类型范围是否足够字符串长度 (VARCHAR) 是否合理是否使用了精确类型DECIMAL处理金额[ ]属性确认是否需要开启动态分区是否需要设置冷热数据策略创建 Doris 数据表是一个融合了数据建模、系统架构和性能调优的综合性工作。理解模型、分区、分桶这三个核心概念是基础而根据具体的业务查询模式和数据增长趋势进行精细化设计则是发挥 Doris 最大效用的关键。避免过早优化但也切忌盲目建表在测试环境中用真实数据模式进行验证是通向生产稳定性的最佳路径。