第一章:Doris 概述与核心架构
1.1 什么是 Apache Doris
| 概念名称 | 说明 | 注意事项 |
|---|
| Apache Doris | 一个高性能、实时的 MPP(大规模并行处理)分析型数据库,原名 Palo,由百度研发,后捐赠给 Apache 基金会。支持高并发低延迟的即席查询。 | Doris 不是关系型数据库(OLTP),而是面向 OLAP 场景设计,适用于实时数据分析。 |
| 开源状态 | Apache 顶级项目,采用 Apache 2.0 许可证,社区活跃,支持多云部署。 | 需关注版本稳定性,生产环境建议使用稳定版本(如 1.2.x、2.0.x)。 |
| 架构特点 | 纯 C++ 编写,无外部依赖(除可选 Broker),部署简单,兼容 MySQL 协议。 | 虽无强依赖,但与 Hive、Kafka 等集成时需部署 Broker 组件。 |
1.2 Doris 的核心特性与适用场景
| 特性名称 | 说明 | 注意事项 |
|---|
| 实时数据分析 | 支持高并发、低延迟的实时数据导入与查询,数据秒级可见。 | 导入频率过高可能影响查询性能,需合理控制导入节奏。 |
| MPP 架构 | 查询时多节点并行执行,充分利用集群资源,提升查询效率。 | 查询性能受 BE 节点数量和资源配置影响较大。 |
| 向量化引擎 | 自 0.15 版本起引入向量化执行引擎,显著提升计算性能。 | 需使用支持向量化的版本(推荐 1.0+),旧版本性能较低。 |
| 兼容 MySQL 协议 | 支持使用 MySQL 客户端或 JDBC 连接,降低接入成本。 | 仅兼容部分 MySQL 语法,不支持事务、存储过程等 OLTP 功能。 |
| 高可用 | FE 支持多副本(Leader/Follower),BE 支持副本间数据冗余。 | 至少需要 3 个 FE 节点实现高可用(奇数个),否则无法选举 Leader。 |
| 适用场景 | 实时数仓、报表系统、用户行为分析、日志分析等。 | 不适用于高频更新、强事务一致性要求的场景。 |
1.3 Doris 架构组件详解(FE、BE、Broker)
| 组件名称 | 说明 | 注意事项 |
|---|
| FE(Frontend) | 负责元数据管理、查询解析、计划生成与调度。分为 Leader、Follower、Observer 三种角色。 | Leader 节点处理写操作和元数据变更;Follower 参与选举;Observer 用于扩展读能力。 |
| BE(Backend) | 负责数据存储、查询执行和数据导入。每个 BE 存储部分分片(Tablet),支持水平扩展。 | BE 节点宕机不影响元数据,但可能导致查询失败或降级。 |
| Broker | 可选组件,用于访问外部存储(如 HDFS、S3、BOS)进行数据导入或导出。 | 使用 Broker Load 时必须部署 Broker;Stream Load 可不依赖 Broker。 |
| 元数据同步 | FE 之间通过 BDBJE 同步元数据,保证一致性。 | 避免手动修改元数据目录,可能导致集群异常。 |
| 查询流程 | 客户端 → FE(解析 SQL,生成计划) → BE(执行任务,返回结果) → FE(合并结果) → 客户端 | 网络延迟或 BE 负载过高可能导致查询变慢。 |
1.4 数据模型概览(Aggregate、Unique、Duplicate)
| 数据模型 | 说明 | 注意事项 |
|---|
| Aggregate 模型 | 相同主键的数据在导入时自动聚合(如 SUM、REPLACE)。适合指标类数据统计。 | 需在建表时指定聚合函数(如 SUM、MAX、MIN),非主键列必须声明聚合方式。 |
| Unique 模型 | 主键唯一,新数据会覆盖旧数据,实现”更新”语义。类似传统数据库的主键更新。 | 从 1.0 版本起支持全局一致性更新;需开启 enable_unique_key_merge_on_write 提升查询性能。 |
| Duplicate 模型 | 不做任何聚合或去重,原始数据全部保留。适合日志、明细数据存储。 | 适合高频写入、无需聚合的场景,但存储开销较大。 |
| 模型选择建议 | 根据业务需求选择:指标汇总 → Aggregate;主键更新 → Unique;明细存储 → Duplicate | 建表后无法更改数据模型,需提前规划。 |
第二章:环境准备与快速入门
2.1 系统要求与环境依赖
| 项目 | 要求 | 注意事项 |
|---|
| 操作系统 | Linux(CentOS 7+/Ubuntu 16.04+) | 推荐使用 CentOS 7 或更高版本,避免使用过旧内核。 |
| CPU | 建议 8 核以上 | FE 可用较少资源,BE 建议高配以支持并行计算。 |
| 内存 | FE:8GB+,BE:16GB+(根据数据量调整) | 内存不足可能导致查询失败或导入超时。 |
| 磁盘 | 建议使用 SSD,预留足够空间(数据量 × 副本数 × 2) | BE 节点需配置 storage_root_path 指定数据目录。 |
| 网络 | 千兆以上局域网,低延迟 | 集群节点间网络不稳定会影响导入和查询性能。 |
| Java 环境 | FE 需要 JDK 1.8 | BE 无需 Java;确保 JAVA_HOME 环境变量正确设置。 |
| GCC 版本 | 若从源码编译,需 GCC 5.3+ | 官方提供编译好的二进制包,通常无需自行编译。 |
2.2 单机部署与集群部署指南
| 部署类型 | 说明 | 注意事项 |
|---|
| 单机部署 | 所有组件(FE、BE)运行在同一台机器,适用于测试和学习。 | 不具备高可用性,生产环境禁用。 |
| 集群部署 | FE 和 BE 分布在多台机器,FE 至少 1 个(推荐 3 个高可用),BE 至少 1 个。 | FE 节点数建议为奇数(1、3、5),便于选举 Leader。 |
| 部署步骤概览 | 解压 Doris 包 → 配置 fe/conf/fe.conf 和 be/conf/be.conf → 启动 FE,再启动 BE → 通过 MySQL 客户端连接 | 首次启动前需确保端口未被占用(FE 默认 9010,BE 默认 9060)。 |
| 配置文件位置 | FE:fe/conf/;BE:be/conf/ | 修改配置后需重启服务生效。 |
| 典型配置项 | priority_networks:指定绑定 IP;meta_dir:FE 元数据路径;storage_root_path:BE 数据路径 | 多网卡环境必须设置 priority_networks,否则可能绑定错误 IP。 |
2.3 服务启动与状态检查
| 操作 | 命令 | 用途 | 注意事项 |
|---|
| 启动 FE | sh bin/start_fe.sh --daemon | 启动前端服务 | 首次启动前需执行 mysql -uroot < fe/sql/create_db.sql 初始化元数据库。 |
| 停止 FE | sh bin/stop_fe.sh --daemon | 停止前端服务 | 建议正常关闭,避免强制 kill 导致元数据损坏。 |
| 启动 BE | sh bin/start_be.sh --daemon | 启动后端服务 | 必须先启动 FE 并添加 BE 节点(通过 SQL)。 |
| 停止 BE | sh bin/stop_be.sh --daemon | 停止后端服务 | 强制停止可能导致正在进行的导入任务失败。 |
| 检查 FE 状态 | http://<fe_host>:8030/api/bootstrap 或查看 fe/log/fe.log | 确认 FE 是否正常启动 | 日志中出现 finished to load meta data 表示启动成功。 |
| 检查 BE 状态 | 查看 be/log/be.INFO | 确认 BE 是否注册到 FE | 日志中出现 master has accepted this backend 表示注册成功。 |
2.4 使用 MySQL 客户端连接 Doris
| 项目 | 说明 | 注意事项 |
|---|
| 连接命令 | mysql -h <fe_host> -P 9030 -u root -p | 默认端口 9030,用户 root 无密码 |
| 客户端工具 | 支持标准 MySQL 客户端、Navicat、DBeaver、JDBC 等 | 仅支持 MySQL 5.7 基础语法,不支持存储过程、视图等高级特性。 |
| 默认用户 | root(管理员),无密码 | 首次登录后建议使用 SET PASSWORD = PASSWORD('xxx'); 设置密码。 |
| 连接失败常见原因 | FE 未启动;防火墙阻止 9030 端口;priority_networks 配置错误 | 检查 FE 日志和网络连通性。 |
| 查看集群状态 | SHOW PROC '/frontends'; 查看 FE 节点状态;SHOW PROC '/backends'; 查看 BE 节点状态 | |
2.5 快速创建数据库与表并插入数据
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建数据库 | CREATE DATABASE [IF NOT EXISTS] db_name; | 创建新的数据库 | CREATE DATABASE example_db; | 数据库名需唯一,避免使用保留字。 |
| 使用数据库 | USE db_name; | 切换当前操作数据库 | USE example_db; | 必须先选择数据库才能建表。 |
| 创建表 | CREATE TABLE [IF NOT EXISTS] table_name (...) | 定义表结构与数据模型 | 见下方示例 | 必须指定分桶列和桶数;主键模型需用 UNIQUE KEY 显式声明。 |
| 插入数据 | INSERT INTO table_name VALUES (...); | 单条或批量插入数据 | INSERT INTO example_tbl VALUES (1001, 'Alice', 25, 8000.00); | 大量数据插入建议使用 Stream Load 或 Broker Load。 |
| 查询数据 | SELECT * FROM table_name; | 查看表中数据 | SELECT * FROM example_tbl; | 支持标准 SQL 查询语法。 |
| 查看表结构 | DESCRIBE table_name; 或 DESC table_name; | 显示表字段信息 | DESC example_tbl; | 可验证建表是否成功。 |
创建表示例:
CREATE TABLE example_tbl (
user_id BIGINT,
name VARCHAR(50),
age INT,
salary DECIMAL(10,2)
)
DISTRIBUTED BY HASH(user_id) BUCKETS 10;
第三章:数据定义语言(DDL)
3.1 数据库操作(CREATE、DROP、ALTER DATABASE)
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建数据库 | CREATE DATABASE [IF NOT EXISTS] db_name [PROPERTIES ("key" = "value")]; | 创建新数据库,可设置属性如副本数 | CREATE DATABASE test_db;
CREATE DATABASE test_db PROPERTIES ("replication_num" = "3"); | 若不指定 replication_num,默认为 1(单副本),生产环境建议设为 3。 |
| 删除数据库 | DROP DATABASE [IF EXISTS] db_name; | 永久删除数据库及其所有表 | DROP DATABASE test_db; | 删除操作不可逆,所有数据将被清除,请谨慎操作。 |
| 修改数据库属性 | ALTER DATABASE db_name SET PROPERTIES ("key" = "value"); | 修改数据库级属性,如副本数 | ALTER DATABASE test_db SET PROPERTIES ("replication_num" = "3"); | 仅支持修改 replication_num 等有限属性;修改后对后续建表生效,不影响已有表。 |
| 查看数据库 | SHOW DATABASES; 或 SHOW CREATE DATABASE db_name; | 列出所有数据库或查看建库语句 | SHOW DATABASES;
SHOW CREATE DATABASE example_db; | SHOW CREATE DATABASE 可用于导出建库语句。 |
3.2 表的创建:CREATE TABLE 详解
| 子句/选项 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 基本建表 | CREATE TABLE [IF NOT EXISTS] [database.]table_name (...) | 定义表结构 | CREATE TABLE tbl1 (id INT, name VARCHAR(20)); | 必须在 USE db; 或指定数据库名。 |
| 声明数据模型 | AGGREGATE KEY (col1, ...) / UNIQUE KEY (col1, ...) / DUPLICATE KEY (col1, ...) | 指定数据模型类型 | UNIQUE KEY(user_id) ... | 必须显式声明 KEY 类型;默认为 DUPLICATE KEY。 |
| 分桶设置 | DISTRIBUTED BY HASH(key) BUCKETS N | 设置分桶列和桶数 | DISTRIBUTED BY HASH(user_id) BUCKETS 10; | 推荐桶数为 BE 数量的 1~10 倍;避免数据倾斜。 |
| 分区设置 | PARTITION BY RANGE (col) (...) | 按范围分区,支持自动/手动分区 | 见下方示例 | 分区列必须是前缀列;建议按时间分区便于管理。 |
| 自动分区 | PARTITION BY RANGE (col) () DISTRIBUTED ... PROPERTIES("dynamic_partition.enable" = "true", ...) | 动态创建未来分区 | 见下方示例 | 需在 FE 配置中启用动态分区功能。 |
| 属性设置 | PROPERTIES ("key" = "value", ...) | 设置表级属性,如副本数、压缩等 | PROPERTIES ("replication_num" = "3", "bloom_filter_columns" = "name", "in_memory" = "false"); | replication_num 建议设为 3;bloom_filter 仅支持 KV 列。 |
分区设置示例:
PARTITION BY RANGE(time_date) (
PARTITION p202501 VALUES LESS THAN ("2025-02-01"),
PARTITION p202502 VALUES LESS THAN ("2025-03-01")
)
自动分区示例:
PROPERTIES (
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.start" = "-3",
"dynamic_partition.end" = "3",
"dynamic_partition.prefix" = "p"
);
3.3 表结构修改:ALTER TABLE 常用操作
| 操作类型 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 添加列 | ALTER TABLE table_name ADD COLUMN col_name type [KEY] [DEFAULT value] [AFTER existing_col]; | 在指定位置添加新列 | ALTER TABLE tbl1 ADD COLUMN age INT DEFAULT '0' AFTER name; | 非主键列可添加;主键模型中 ADD COLUMN 有约束。 |
| 删除列 | ALTER TABLE table_name DROP COLUMN col_name; | 删除指定列 | ALTER TABLE tbl1 DROP COLUMN age; | 不支持删除主键列或分桶列;删除后数据不可恢复。 |
| 修改列类型 | ALTER TABLE table_name MODIFY COLUMN col_name new_type; | 更改列的数据类型 | ALTER TABLE tbl1 MODIFY COLUMN name VARCHAR(50); | 仅支持扩大类型(如 INT → BIGINT),不支持缩小或改变语义。 |
| 重命名列 | ALTER TABLE table_name CHANGE COLUMN old_name new_name new_type; | 修改列名和类型 | ALTER TABLE tbl1 CHANGE COLUMN name user_name VARCHAR(50); | 必须重新指定类型,即使不变。 |
| 添加分区 | ALTER TABLE table_name ADD PARTITION partition_name VALUES LESS THAN ("value"); | 手动添加新分区 | ALTER TABLE tbl1 ADD PARTITION p202503 VALUES LESS THAN ("2025-04-01"); | 分区值必须大于当前最大分区。 |
| 删除分区 | ALTER TABLE table_name DROP PARTITION partition_name; | 删除指定分区 | ALTER TABLE tbl1 DROP PARTITION p202501; | 删除后该分区数据永久丢失。 |
| 暂停/恢复作业 | ALTER TABLE table_name [CANCEL] SCHEMA CHANGE; | 取消正在进行的 schema 变更 | ALTER TABLE tbl1 CANCEL SCHEMA CHANGE; | schema change 是异步操作,可通过 SHOW ALTER TABLE 查看状态。 |
3.4 表与数据库的删除:DROP TABLE / DATABASE
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 删除表 | DROP TABLE [IF EXISTS] [database.]table_name [FORCE]; | 删除指定表 | DROP TABLE tbl1; | 普通删除进入回收站,可恢复;加 FORCE 则永久删除。 |
| 强制删除表 | DROP TABLE table_name FORCE; | 绕过回收站,永久删除 | DROP TABLE tbl1 FORCE; | 无法恢复,请谨慎使用。 |
| 恢复表 | RECOVER TABLE [database.]table_name; | 从回收站恢复已删除表 | RECOVER TABLE tbl1; | 仅适用于未加 FORCE 的删除操作。 |
| 查看回收站 | SHOW RECYCLEBIN; | 显示被删除但可恢复的对象 | SHOW RECYCLEBIN; | 可查看 TableName、OriginName、DropTime 等信息。 |
| 清空回收站 | ADMIN EMPTY TRASH; | 手动清理回收站中过期数据 | ADMIN EMPTY TRASH; | 回收站默认 1 天自动清理,也可手动触发。 |
| 删除数据库 | DROP DATABASE db_name; | 删除数据库及所有表 | DROP DATABASE test_db; | 与 DROP TABLE 类似,也支持回收站机制。 |
3.5 分区(Partition)与分桶(Bucket)策略配置
| 概念 | 说明 | 注意事项 |
|---|
| 分区(Partition) | 将大表按某一列(通常是时间)划分为多个逻辑部分,提升查询效率和管理便利性 | 支持 RANGE 和 LIST 分区;分区列必须是前缀列;建议按时间分区。 |
| 分桶(Bucket) | 在每个分区内,按哈希值将数据进一步分散到多个桶中,实现数据均衡和并行处理 | 分桶列建议选择高基数列(如 ID);桶数应为 BE 数量的整数倍,避免倾斜。 |
| 分区裁剪 | 查询时自动跳过不相关的分区,显著提升性能 | WHERE 条件中需包含分区列才能触发裁剪。 |
| 分桶剪枝 | 查询时仅扫描相关桶,减少 I/O | 依赖分桶列在查询条件中出现。 |
| 动态分区 | 自动按时间单位(DAY/WEEK/MONTH)创建未来分区 | 需在表属性中启用并配置 dynamic_partition.* 参数;适合日志类表。 |
| 多级分区 | 支持先 RANGE 再 HASH 的复合分区方式 | 语法:PARTITION BY RANGE(...) ( ... ) DISTRIBUTED BY HASH(...) BUCKETS N; |
第四章:数据操作语言(DML)
4.1 数据导入:LOAD、BROKER LOAD、STREAM LOAD、ROUTINE LOAD
| 导入方式 | 语法/方式 | 用途 | 代码示例 | 注意事项 |
|---|
| STREAM LOAD | HTTP PUT 请求或 curl 命令 | 实时导入本地或 HTTP 数据,同步返回结果 | curl --location-trusted -u user:passwd -T data.csv http://fe_host:8030/api/db1/tbl1/_stream_load | 支持 CSV、JSON、Parquet 等格式;适合中小批量实时导入。 |
| BROKER LOAD | LOAD LABEL db.label (DATA INFILE (...) INTO TABLE ...) | 从 HDFS/S3/BOS 等外部存储异步导入大数据 | 见下方示例 | 需部署 Broker;适合离线批量导入;支持事务性。 |
| ROUTINE LOAD | CREATE ROUTINE LOAD ... FROM KAFKA ... | 从 Kafka 持续订阅数据,实现流式导入 | 见下方示例 | 支持 Exactly-Once 语义;需监控消费延迟。 |
| INSERT INTO | INSERT INTO table VALUES (...) 或 INSERT INTO SELECT ... | 单条或批量插入,或从其他表导入 | INSERT INTO tbl1 VALUES (1, 'a');
INSERT INTO tbl2 SELECT * FROM tbl1; | 大量数据插入性能较差,建议用于测试或小数据量。 |
| MySQL Load | LOAD DATA LOCAL INFILE ... | 通过 MySQL 协议导入本地文件 | LOAD DATA LOCAL INFILE 'data.csv' INTO TABLE tbl1; | 实际走的是 Stream Load 协议,需客户端支持。 |
BROKER LOAD 示例:
LOAD LABEL example_db.label1 (
DATA INFILE("hdfs://path/*.csv")
INTO TABLE tbl1
COLUMNS TERMINATED BY ","
);
ROUTINE LOAD 示例:
CREATE ROUTINE LOAD example_db.job1 ON tbl1
PROPERTIES("desired_concurrent_number"="1")
FROM KAFKA (
"kafka_broker_list" = "kafka:9092",
"kafka_topic" = "doris"
);
4.2 数据查询:SELECT 基础语法
| 子句 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 基本查询 | SELECT col1, col2 FROM table; | 选择指定列 | SELECT id, name FROM tbl1; | 使用 * 可能影响性能,建议明确列名。 |
| 条件过滤 | SELECT ... WHERE condition; | 按条件筛选数据 | SELECT * FROM tbl1 WHERE age > 20; | 尽量使用索引列(前缀列、Bloom Filter 列)提升性能。 |
| 去重查询 | SELECT DISTINCT col FROM table; | 返回唯一值 | SELECT DISTINCT name FROM tbl1; | 大数据量去重消耗内存,可能触发 spill。 |
| 限制返回 | SELECT ... LIMIT N; | 限制结果行数 | SELECT * FROM tbl1 LIMIT 10; | 常用于调试或分页查询(配合 ORDER BY)。 |
| 排序查询 | SELECT ... ORDER BY col [ASC|DESC]; | 按列排序 | SELECT * FROM tbl1 ORDER BY age DESC; | 排序为全局操作,大数据量可能较慢。 |
| 别名使用 | SELECT col AS alias FROM table; | 为列或表设置别名 | SELECT name AS user_name FROM tbl1 t; | 提高 SQL 可读性。 |
| 表达式计算 | SELECT col1 + col2 FROM table; | 支持算术、逻辑、函数表达式 | SELECT salary * 1.1 FROM tbl1; | Doris 内置丰富函数(数学、字符串、日期等)。 |
4.3 数据更新与删除:UPDATE、DELETE(基于 Unique 模型)
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 删除数据 | DELETE FROM table WHERE condition; | 根据条件删除行(仅 Unique 模型) | DELETE FROM tbl1 WHERE id = 1001; | 必须包含主键列在 WHERE 中;不支持非主键条件删除。 |
| 更新数据 | UPDATE table SET col = value WHERE key = val; | 更新指定行的列值 | UPDATE tbl1 SET name = 'Bob' WHERE id = 1001; | 仅 2.0+ 版本支持 UPDATE 语句;仍需基于主键。 |
| 删除限制 | 支持 AND 多条件,但必须包含所有主键列 | DELETE FROM tbl1 WHERE id = 1 AND name = 'a'; | 不支持 OR、IN、LIKE 等复杂条件。 | |
| 异步执行 | 删除操作异步执行,立即返回任务 ID | 返回 {"label":"delete_123", "status":"PENDING"} | 可通过 SHOW DELETE FROM table_name; 查看状态。 | |
| 性能影响 | 大量删除可能导致查询性能下降 | — | 删除后建议执行 COMPACT 合并数据版本。 | |
4.4 批量插入:INSERT INTO … VALUES / SELECT
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 批量 VALUES | INSERT INTO table VALUES (...), (...), ...; | 一次插入多行数据 | INSERT INTO tbl1 VALUES (1,'a'),(2,'b'); | 行数不宜过多(建议 < 1000),否则可能超时。 |
| 插入 SELECT | INSERT INTO table SELECT ... FROM other_table; | 从其他表导入数据 | INSERT INTO tbl2 SELECT * FROM tbl1; | 适合表间迁移或 ETL 场景。 |
| 异步插入 | INSERT INTO ... SELECT ... 默认同步 | 同步执行,等待完成 | — | 大数据量插入建议使用 Broker Load 或 Stream Load。 |
| 插入分区表 | 自动写入对应分区 | 按分区列值自动路由 | INSERT INTO partitioned_tbl VALUES ('2025-01-01', 100); | 确保数据符合分区范围,否则报错。 |
| 错误处理 | 可通过 SET enable_insert_strict = false; 忽略错误行 | 容忍部分数据错误 | SET enable_insert_strict = false; INSERT INTO ... | 开启后仅记录错误日志,部分数据可能丢失。 |
4.5 导入作业管理与状态查询
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 查看导入作业 | SHOW LOAD [FROM db] [WHERE label = "xxx"]; | 查看所有或指定导入任务状态 | SHOW LOAD FROM example_db; | 显示状态(FINISHED、CANCELLED)、进度、错误信息等。 |
| 查看 Broker Load | SHOW LOAD WHERE label = "label1"; | 查看异步导入状态 | SHOW LOAD WHERE label = "job1"; | 支持分页查询,LIMIT 控制返回数量。 |
| 查看 Stream Load | 通过返回的 Label 在 SHOW LOAD 中查询 | Stream Load 也生成 label | SHOW LOAD WHERE label = "stream_load_1"; | 即使同步返回成功,也可查详情。 |
| 查看 Routine Load | SHOW ROUTINE LOAD [FROM db] [FOR job_name]; | 查看流式导入状态 | SHOW ROUTINE LOAD FOR job1; | 可查看消费位点、速度、错误日志。 |
| 取消导入作业 | CANCEL LOAD FROM db WHERE label = "xxx"; | 终止正在运行的导入任务 | CANCEL LOAD FROM example_db WHERE label = "job1"; | 仅对未完成任务有效。 |
| 查看错误行 | SHOW LOAD WARNINGS FROM db WHERE label = "xxx"; | 查看导入失败的具体数据行 | SHOW LOAD WARNINGS FROM example_db WHERE label = "job1"; | 需在导入时启用 max_filter_ratio > 0 才能捕获。 |
第五章:数据查询语言(DQL)深入
5.1 SELECT 子句与列选择
| 语法项 | 语法格式 | 用途 | 代码示例 | 注意事项 |
|---|
| 选择所有列 | SELECT * FROM table; | 查询表中所有字段 | SELECT * FROM employee; | 不推荐用于生产,影响性能且不明确字段。 |
| 选择指定列 | SELECT col1, col2 FROM table; | 仅返回需要的列 | SELECT name, age FROM employee; | 减少 I/O 和网络传输,提升查询效率。 |
| 列别名 | SELECT col AS alias FROM table; | 为列设置别名便于引用或展示 | SELECT salary AS sal, name AS full_name FROM employee; | 别名可用于 ORDER BY 或外部查询引用。 |
| 表达式列 | SELECT col1 + col2 FROM table; | 返回计算结果 | SELECT id, salary * 1.1 AS new_salary FROM employee; | 支持算术、字符串拼接、函数调用等表达式。 |
| 常量列 | SELECT col, 'fixed' FROM table; | 添加固定值列 | SELECT name, 'CN' AS country FROM employee; | 适用于补全维度信息。 |
| 去重列值 | SELECT DISTINCT col FROM table; | 返回唯一值 | SELECT DISTINCT dept FROM employee; | 大数据量时消耗内存高,可能触发磁盘排序(spill)。 |
5.2 WHERE 条件过滤与表达式
| 条件类型 | 语法格式 | 用途 | 代码示例 | 注意事项 |
|---|
| 比较操作 | =, !=, <, >, <=, >= | 基本比较 | SELECT * FROM emp WHERE age >= 30; | 推荐在分区列、分桶列上使用以触发剪枝。 |
| 范围查询 | BETWEEN ... AND ... | 匹配区间值 | SELECT * FROM emp WHERE age BETWEEN 20 AND 30; | 等价于 col >= val1 AND col <= val2。 |
| 枚举匹配 | IN (val1, val2, ...) | 匹配多个离散值 | SELECT * FROM emp WHERE dept IN ('HR', 'IT'); | IN 列表过大(>1000)可能影响性能。 |
| 模式匹配 | LIKE 'pattern' | 模糊匹配(支持 % 和 _) | SELECT * FROM emp WHERE name LIKE 'A%'; | 不区分大小写;前缀匹配性能较好,后缀匹配较差。 |
| 正则匹配 | REGEXP 'pattern' 或 RLIKE | 使用正则表达式过滤 | SELECT * FROM emp WHERE name REGEXP '^A.*'; | 性能低于 LIKE,仅用于复杂模式。 |
| 空值判断 | IS NULL, IS NOT NULL | 判断是否为空 | SELECT * FROM emp WHERE phone IS NULL; | 不能用 = NULL 判断空值。 |
| 逻辑组合 | AND, OR, NOT | 组合多个条件 | SELECT * FROM emp WHERE age > 25 AND dept = 'IT'; | 注意优先级,复杂逻辑建议加括号。 |
5.3 GROUP BY 与聚合函数
| 聚合函数 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 计数 | COUNT(*), COUNT(col) | 统计行数或非空值数量 | SELECT dept, COUNT(*) FROM emp GROUP BY dept; | COUNT(*) 包含 NULL,COUNT(col) 不包含。 |
| 求和 | SUM(col) | 数值列求和 | SELECT dept, SUM(salary) FROM emp GROUP BY dept; | 仅适用于数值类型。 |
| 最大值 | MAX(col) | 获取最大值 | SELECT MAX(age) FROM emp; | 支持数值、字符串、日期等类型。 |
| 最小值 | MIN(col) | 获取最小值 | SELECT MIN(salary) FROM emp; | 同上。 |
| 平均值 | AVG(col) | 计算平均值 | SELECT AVG(salary) FROM emp; | 结果为 DECIMAL 类型,避免精度丢失。 |
| 去重计数 | COUNT(DISTINCT col) | 统计唯一值数量 | SELECT COUNT(DISTINCT dept) FROM emp; | 内存消耗大,大数据量建议使用近似函数 NDV()。 |
| 分组查询 | GROUP BY col1, col2 | 按一或多列分组聚合 | SELECT dept, gender, AVG(salary) FROM emp GROUP BY dept, gender; | SELECT 中非聚合列必须出现在 GROUP BY 中。 |
5.4 HAVING 过滤聚合结果
| 语法项 | 语法格式 | 用途 | 代码示例 | 注意事项 |
|---|
| HAVING 子句 | HAVING condition | 对 GROUP BY 后的结果进行过滤 | SELECT dept, AVG(salary) FROM emp GROUP BY dept HAVING AVG(salary) > 8000; | HAVING 用于过滤聚合值,WHERE 用于过滤原始数据。 |
| 使用聚合函数 | HAVING COUNT(*) > 5 | 基于统计结果过滤 | SELECT dept FROM emp GROUP BY dept HAVING COUNT(*) > 10; | HAVING 条件中必须使用聚合函数或分组列。 |
| 多条件组合 | HAVING cond1 AND cond2 | 组合多个过滤条件 | SELECT dept, AVG(salary) FROM emp GROUP BY dept HAVING AVG(salary) > 5000 AND COUNT(*) > 5; | 支持逻辑运算符。 |
| 与 WHERE 区别 | WHERE 在分组前过滤,HAVING 在分组后过滤 | — | — | 先执行 WHERE,再 GROUP BY,最后 HAVING。 |
5.5 ORDER BY 与 LIMIT
| 子句 | 语法格式 | 用途 | 代码示例 | 注意事项 |
|---|
| 排序 | ORDER BY col [ASC|DESC] | 按列排序结果集 | SELECT * FROM emp ORDER BY salary DESC; | 默认升序 ASC;多列排序时按顺序生效。 |
| 多列排序 | ORDER BY col1, col2 DESC | 按多个字段排序 | SELECT * FROM emp ORDER BY dept, salary DESC; | 先按 dept 升序,再按 salary 降序。 |
| 限制行数 | LIMIT N | 返回前 N 行 | SELECT * FROM emp LIMIT 10; | 常用于分页或查看样本数据。 |
| 分页查询 | LIMIT offset, count 或 LIMIT count OFFSET offset | 实现分页 | SELECT * FROM emp LIMIT 10 OFFSET 20; | 大偏移量(offset 很大)性能差,建议用游标或时间戳分页。 |
| 排序+限制 | ORDER BY ... LIMIT N | 获取 Top-N 结果 | SELECT name, salary FROM emp ORDER BY salary DESC LIMIT 5; | Doris 会对该类查询进行优化。 |
5.6 JOIN 操作:INNER、LEFT、RIGHT、FULL、CROSS
| JOIN 类型 | 语法格式 | 用途 | 代码示例 | 注意事项 |
|---|
| 内连接 | INNER JOIN 或 JOIN | 返回两表匹配的行 | SELECT * FROM A JOIN B ON A.id = B.a_id; | 最常用,性能较好。 |
| 左外连接 | LEFT JOIN 或 LEFT OUTER JOIN | 返回左表全部行,右表无匹配则补 NULL | SELECT * FROM A LEFT JOIN B ON A.id = B.a_id; | 常用于查找”未关联”数据。 |
| 右外连接 | RIGHT JOIN 或 RIGHT OUTER JOIN | 返回右表全部行,左表无匹配则补 NULL | SELECT * FROM A RIGHT JOIN B ON A.id = B.a_id; | 可通过交换表顺序用 LEFT JOIN 替代。 |
| 全外连接 | FULL JOIN 或 FULL OUTER JOIN | 返回两表所有行,无匹配则补 NULL | SELECT * FROM A FULL JOIN B ON A.id = B.a_id; | 性能较差,内存消耗大,慎用。 |
| 交叉连接 | CROSS JOIN 或逗号 | 返回两表笛卡尔积 | SELECT * FROM A CROSS JOIN B; | 行数 = A行数 × B行数,极易导致 OOM,避免使用。 |
| ON 条件 | ON col1 = col2 | 指定连接条件 | ON A.id = B.a_id | 必须包含等值条件;支持多列。 |
| USING 子句 | USING (col) | 简化同名列连接 | SELECT * FROM A JOIN B USING (id); | 要求两表该列名相同。 |
5.7 子查询与 CTE(Common Table Expressions)
| 结构 | 语法格式 | 用途 | 代码示例 | 注意事项 |
|---|
| 标量子查询 | (SELECT col FROM table WHERE ...) | 返回单值,用于表达式 | SELECT * FROM emp WHERE salary > (SELECT AVG(salary) FROM emp); | 必须返回单行单列,否则报错。 |
| 行子查询 | (SELECT col1, col2 FROM ...) | 返回单行多列 | SELECT * FROM emp WHERE (dept, salary) = (SELECT dept, MAX(salary) FROM emp GROUP BY dept); | 较少使用,需确保返回一行。 |
| 表子查询 | FROM (SELECT ...) | 作为临时表使用 | SELECT t.dept, t.cnt FROM (SELECT dept, COUNT(*) cnt FROM emp GROUP BY dept) t; | 必须为子查询指定别名。 |
| CTE(WITH) | WITH cte_name AS (SELECT ...) | 定义命名临时结果集 | 见下方示例 | 可提高可读性,支持递归(有限)。 |
| 关联子查询 | 子查询引用外层表列 | 实现逐行判断 | SELECT e1.name FROM emp e1 WHERE e1.salary > (SELECT AVG(salary) FROM emp e2 WHERE e2.dept = e1.dept); | 性能较差,尽量改写为 JOIN。 |
CTE 示例:
WITH top_salaries AS (
SELECT * FROM emp ORDER BY salary DESC LIMIT 10
)
SELECT * FROM top_salaries;
5.8 窗口函数(Window Functions)基础
| 函数类别 | 语法格式 | 用途 | 代码示例 | 注意事项 |
|---|
| 排名函数 | ROW_NUMBER(), RANK(), DENSE_RANK() | 行内排名 | SELECT name, salary, RANK() OVER (ORDER BY salary DESC) rk FROM emp; | ROW_NUMBER 不跳号,RANK 跳号,DENSE_RANK 不跳号。 |
| 分布函数 | PERCENT_RANK(), CUME_DIST() | 计算相对位置 | SELECT name, salary, PERCENT_RANK() OVER (ORDER BY salary) pct FROM emp; | 用于统计分布。 |
| 前后行函数 | LAG(col, n), LEAD(col, n) | 访问前/后第 n 行 | SELECT date, sales, LAG(sales, 1) OVER (ORDER BY date) prev_sales FROM daily_sales; | 常用于同比、环比计算。 |
| 聚合窗口函数 | SUM(...) OVER (...), AVG(...) OVER (...) | 窗口内聚合 | SELECT dept, name, salary, SUM(salary) OVER (PARTITION BY dept) dept_total FROM emp; | 支持所有聚合函数作为窗口函数。 |
| 窗口定义 | OVER ([PARTITION BY ...] [ORDER BY ...] [frame_clause]) | 定义窗口范围 | SUM(sales) OVER (PARTITION BY region ORDER BY date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) | frame_clause 控制窗口行范围。 |
第六章:数据模型与高级特性
6.1 Aggregate 模型原理与使用场景
| 概念 | 说明 | 注意事项 |
|---|
| 核心原理 | 相同主键的数据在导入时自动按指定聚合函数合并(如 SUM、REPLACE、MAX) | 适用于指标类数据(如 PV、UV、销售额)。 |
| 聚合列定义 | 非主键列必须声明聚合方式,如 SUM(sales), MAX(last_visit) | 建表时必须明确每个非主键列的聚合函数。 |
| 导入合并 | 导入时 Doris 自动查找相同主键行并合并 | 查询时无需 GROUP BY 主键,性能高。 |
| 适用场景 | 日志聚合、指标统计表、预聚合宽表 | 不适用于需要保留明细的场景。 |
| 局限性 | 无法还原原始明细数据;不支持 UPDATE/DELETE 操作 | 一旦聚合,原始数据不可见。 |
6.2 Unique 模型:主键更新机制
| 特性 | 说明 | 注意事项 |
|---|
| 主键唯一性 | 每行数据由主键唯一标识,新数据覆盖旧数据 | 实现”UPSERT”语义。 |
| 更新方式 | 导入时按主键查找并替换整行 | 支持 Stream Load、Broker Load、Routine Load。 |
| 存储模式 | 从 1.0 版本起支持 Merge-on-Write 或 Write-on-Read | 建议开启 enable_unique_key_merge_on_write 提升查询性能。 |
| 删除支持 | DELETE FROM table WHERE key = val; 可删除指定行 | 必须包含所有主键列在 WHERE 中。 |
| 适用场景 | 用户档案表、订单状态更新、缓慢变化维(SCD) | 替代传统数据库实现轻量级实时更新。 |
6.3 Duplicate 模型:明细数据存储
| 特性 | 说明 | 注意事项 |
|---|
| 数据存储 | 不做任何聚合或去重,原始数据全部保留 | 适合存储日志、行为事件等明细数据。 |
| 建表语法 | 使用 DUPLICATE KEY(...) 或省略 KEY 定义 | 默认模型,无需特殊声明。 |
| 查询灵活性 | 支持任意维度的 GROUP BY 和聚合 | 适合即席查询和灵活分析。 |
| 存储开销 | 存储成本高,无自动压缩 | 需依赖列存压缩和分区管理控制成本。 |
| 适用场景 | 用户行为日志、交易流水、原始数据接入层 | 通常作为数据仓库的明细层(DWD)。 |
6.4 物化视图(Materialized View)创建与管理
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建物化视图 | CREATE MATERIALIZED VIEW mv_name AS SELECT ... | 预计算并存储查询结果 | 见下方示例 | 自动加速匹配的查询。 |
| 查询自动路由 | 查询时自动匹配物化视图 | 无需修改 SQL | SELECT dept, SUM(salary) FROM emp GROUP BY dept; → 自动命中 emp_mv | 要求查询可被物化视图覆盖。 |
| 查看物化视图 | SHOW MATERIALIZED VIEWS; | 列出所有物化视图 | SHOW MATERIALIZED VIEWS FROM db; | 可查看状态、刷新方式等。 |
| 删除物化视图 | DROP MATERIALIZED VIEW mv_name; | 删除指定物化视图 | DROP MATERIALIZED VIEW emp_mv; | 删除后不再加速相关查询。 |
| 刷新机制 | 自动同步基础表数据变更 | 导入时自动更新物化视图 | — | 不支持异步刷新,保证一致性。 |
创建物化视图示例:
CREATE MATERIALIZED VIEW emp_mv
AS SELECT dept, SUM(salary) sum_sal
FROM emp GROUP BY dept;
6.5 Rollup 表的构建与查询加速原理
| 概念 | 说明 | 注意事项 |
|---|
| Rollup 表 | 基于原表的列子集构建的聚合表,用于加速特定查询 | 类似物化视图,但仅支持基于分桶列的聚合。 |
| 创建语法 | ALTER TABLE table ADD ROLLUP rollup_name (col1, col2, ...); | 添加 Rollup 表 |
| 查询加速 | 查询时自动匹配最合适的 Rollup 表 | 无需修改 SQL |
| 数据同步 | 导入时自动更新 Rollup 数据 | 保证一致性 |
| 删除 Rollup | ALTER TABLE table DROP ROLLUP rollup_name; | 移除 Rollup 表 |
第七章:性能调优与运维管理
7.1 查询性能分析:EXPLAIN 与 PROFILE
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 查看执行计划 | EXPLAIN SELECT ... | 显示 SQL 的逻辑执行计划 | EXPLAIN SELECT * FROM emp WHERE id = 1001; | 分析是否命中索引、分区、Rollup 等。 |
| 查看详细 Profile | SHOW PROFILE 或访问 Web UI | 查看物理执行耗时、算子统计 | 执行查询后:SHOW PROFILE; | 需开启 enable_profile = true(默认开启)。 |
| Profile 内容项 | Fragment, Instance, Operator, Actual Rows, Total Time | 定位性能瓶颈(如扫描、Join、Sort) | — | 关注 Conjuncts(过滤条件)、Cardinality(行数估算)。 |
| 启用向量化分析 | EXPLAIN (FORMAT JSON) SELECT ... | 获取 JSON 格式执行计划 | EXPLAIN (FORMAT JSON) SELECT ... | 用于程序解析或深度分析。 |
| 分析延迟原因 | 结合 EXPLAIN 和 PROFILE 判断:扫描数据量大、Join 倾斜、内存不足导致 Spill | — | 大表 Join 建议使用 Colocate Join 或 Bucket Shuffle Join。 | |
7.2 分区与分桶设计优化
| 设计原则 | 说明 | 注意事项 |
|---|
| 分区策略选择 | 按时间(DAY/MONTH)、按地域/业务线(LIST) | 建议使用 RANGE 分区,便于生命周期管理;避免过多小分区(>1000)。 |
| 分区粒度 | DAY > HOUR > MONTH(按数据量权衡) | 日增数据 < 1GB 可按月;>10GB 建议按天或小时。 |
| 分区剪枝 | WHERE 条件包含分区列可跳过无关分区 | WHERE dt = '2025-01-01' 可剪枝;WHERE substring(dt,1,7)='2025-01' 无法剪枝。 |
| 分桶列选择 | 选择高基数、常用于等值条件或 Join 的列(如 user_id) | 避免低基数列(如 gender)导致数据倾斜。 |
| 桶数设置 | 建议为 BE 节点数的 110 倍,总桶数 10100 倍数据量 | 示例:3 BE 节点 → 每表 10~30 桶;大表可设 100+ 桶。 |
| 动态分区配置 | 使用 PROPERTIES 自动管理未来分区 | 见下方示例 |
动态分区配置示例:
PROPERTIES (
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.end" = "3",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "10"
);
7.3 索引机制:前缀索引与 Bloom Filter
| 索引类型 | 说明 | 代码示例 | 注意事项 |
|---|
| 前缀索引 | Doris 自动为排序列前 36 字节创建前缀索引,加速等值和范围查询 | 建表时 KEY 列即为排序列:DUPLICATE KEY(k1, k2) → 索引 k1, k2 | 前缀索引仅对排序列有效;建议将高频过滤列放在前面。 |
| Bloom Filter | 用于快速判断某值是否存在,减少无效扫描 | PROPERTIES ("bloom_filter_columns" = "user_id,email"); | 仅支持等值查询(=、IN);不支持字符串前缀匹配。 |
| 索引生效条件 | WHERE 包含前缀列或 Bloom Filter 列 | WHERE user_id = 1001 → 触发 Bloom Filter | 复合条件中需包含索引列。 |
| 查看索引效果 | 通过 EXPLAIN 查看 PREDICATES 和 CARDINALITY | 若 CARDINALITY 估算准确,说明索引有效 | 估算偏差大可能影响 Join 策略选择。 |
| 索引限制 | 不支持二级索引;Bloom Filter 不支持 LIKE、!= | — | 大宽表建议合理设计列序和索引列。 |
7.4 BE 存储路径管理与扩容
| 操作 | 语法/配置 | 用途 | 注意事项 |
|---|
| 配置存储路径 | 在 be.conf 中设置:storage_root_path = /path/to/storage,medium=SSD | 指定 BE 数据存储目录及介质类型 | 可配置多个路径,用逗号分隔;推荐使用 SSD。 |
| 查看路径状态 | SHOW PROC '/backends'; | 查看 BE 节点存储使用情况 | 关注 DataUsedCapacity、DiskUsedPercent。 |
| 添加新路径 | 修改 be.conf 并重启 BE | 扩展单节点存储容量 | 新路径需有足够权限,格式正确。 |
| BE 扩容 | 部署新 BE 节点 → 启动 BE → FE 自动注册 | 增加集群存储和计算能力 | 扩容后数据会自动均衡(需时间)。 |
| 数据均衡策略 | FE 自动调度 Tablet 均衡分布 | 避免数据倾斜 | 可通过 ADMIN SHOW REPLICA 查看分布。 |
| 缩容 BE | ALTER SYSTEM DROP BACKEND "host:port"; | 移除 BE 节点 | 确保数据已迁移完成,避免数据丢失。 |
7.5 FE 高可用配置(Follower 与 Observer)
| 角色 | 说明 | 配置方式 | 注意事项 |
|---|
| Leader | 处理元数据写操作(建表、导入等) | 自动选举产生 | 仅有一个 Leader。 |
| Follower | 参与选举,可处理元数据读操作 | 在 fe.conf 中设置 edit_log_port = 9010;启动多个 FE 并通过 mysql -h fe_host -P 9010 -u root 添加 | 至少 3 个 Follower 实现高可用(共 3~5 个 FE)。 |
| Observer | 仅同步元数据,不参与选举,用于扩展读能力 | 配置同 Follower,启动后执行:ALTER SYSTEM ADD OBSERVER "host:9010"; | 适用于元数据读压力大的场景。 |
| 元数据同步 | 使用 BDBJE 实现日志复制 | — | 确保 edit_log_port 网络互通。 |
| 高可用部署 | 推荐 3 FE(1 Leader + 2 Follower)+ N BE | 实现 FE 和 BE 层高可用 | 避免 FE 单点故障。 |
| 查看 FE 状态 | SHOW PROC '/frontends'; | 确认角色和存活状态 | Role 列显示 LEADER、FOLLOWER、OBSERVER。 |
7.6 监控指标与日志查看
| 监控项 | 查看方式 | 说明 | 注意事项 |
|---|
| FE 监控 | Web UI: http://fe_host:8030;Metrics: http://fe_host:8030/metrics | 查看查询 QPS、导入速率、元数据大小 | 可集成 Prometheus + Grafana。 |
| BE 监控 | Web UI: http://be_host:8040;Metrics: http://be_host:8040/metrics | 查看磁盘使用、查询延迟、内存占用 | 关注 tablet_writer 性能。 |
| 查询日志 | fe/log/fe.warn.log, be/log/be.INFO | 定位错误和慢查询 | fe.audit.log 记录所有 SQL(需开启)。 |
| 慢查询日志 | 开启 qe_slow_log_ms(如 1000ms) | 记录超过阈值的查询 | 日志位于 fe/log/ 目录下。 |
| 告警配置 | 结合 Prometheus + Alertmanager | 设置磁盘、CPU、查询延迟告警 | 生产环境必备。 |
| 常用命令 | SHOW PROC '/statistic'; SHOW PROC '/current_tasks'; | 查看集群统计和当前任务 | 用于实时诊断。 |
第八章:安全与权限管理
8.1 用户与角色管理(CREATE USER、GRANT、REVOKE)
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建用户 | CREATE USER 'user'@'host' [IDENTIFIED BY 'password']; | 添加新用户 | CREATE USER 'analyst'@'%' IDENTIFIED BY '123456'; | 'host' 支持 %(任意)、192.168.%(网段)。 |
| 删除用户 | DROP USER 'user'@'host'; | 删除用户 | DROP USER 'test'@'%'; | 删除后其权限自动清除。 |
| 创建角色 | CREATE ROLE role_name; | 定义角色便于权限管理 | CREATE ROLE analyst_role; | 角色可跨用户复用。 |
| 授予角色 | GRANT role_name TO 'user'@'host'; | 将角色分配给用户 | GRANT analyst_role TO 'analyst'@'%'; | 用户可拥有多个角色。 |
| 查看用户权限 | SHOW GRANTS FOR 'user'@'host'; | 显示用户拥有的权限 | SHOW GRANTS FOR 'analyst'@'%'; | 包括直接权限和角色继承权限。 |
8.2 权限体系详解(数据库、表、资源级权限)
| 权限类型 | 支持对象 | 语法示例 | 说明 | 注意事项 |
|---|
| GLOBAL 级 | 集群级资源 | GRANT ADMIN PRIVILEGES ON *.* TO user; | 超级管理员权限 | 包含所有权限,慎用。 |
| DATABASE 级 | 数据库 | GRANT SELECT ON DATABASE db1 TO user; | 控制数据库操作权限 | 可授 SELECT, INSERT, ALTER, DROP 等。 |
| TABLE 级 | 表 | GRANT SELECT, INSERT ON TABLE tbl1 TO user; | 精细化控制表操作 | 最常用权限粒度。 |
| RESOURCE 级 | 外部资源(如 Spark、HDFS) | GRANT USAGE ON RESOURCE 'spark01' TO user; | 控制资源使用权限 | 用于 Broker Load、Spark Load 等场景。 |
| USAGE 权限 | 数据库/资源 | GRANT USAGE ON DATABASE db1 TO user; | 允许访问数据库(但不能查表) | 通常与表权限配合使用。 |
| 撤销权限 | REVOKE privilege ON object FROM user; | 移除用户权限 | REVOKE INSERT ON TABLE tbl1 FROM 'user'@'%'; | 撤销后立即生效。 |
8.3 认证方式配置(LDAP、SSL 等简介)
| 认证方式 | 配置说明 | 用途 | 注意事项 |
|---|
| 原生密码认证 | 默认方式,用户密码存储在 FE 元数据中 | 简单易用 | 建议定期修改密码。 |
| LDAP 认证 | 配置 auth_type = ldap 在 fe.conf | 集成企业 LDAP/AD 统一认证 | 需配置 LDAP 服务器地址、DN、搜索过滤器。 |
| SSL 加密连接 | 配置 SSL 证书,启用 enable_ssl | 加密客户端与 FE 之间通信 | 提升数据传输安全性,防止窃听。 |
| Kerberos(有限支持) | 结合 Hadoop 生态使用 | 企业级安全认证 | Doris 原生支持较弱,通常通过 Broker 层实现。 |
| 密码策略 | 通过 PASSWORD_HISTORY、PASSWORD_LOCK_TIME 等属性 | 增强密码安全性 | SET PASSWORD_POLICY = ...(部分版本支持)。 |
| 安全建议 | 禁用 root 远程登录;使用最小权限原则;启用审计日志 | 提升整体安全性 | 生产环境必须配置访问白名单和监控告警。 |
第九章:生态集成与外部数据源
9.1 外部表(External Table)概述
| 概念 | 说明 | 注意事项 |
|---|
| 外部表定义 | 不在 Doris 中存储数据,仅保存元数据和连接信息,查询时实时访问外部系统 | 实现”读时建模”(Schema-on-Read) |
| 支持类型 | MySQL、Kafka(通过 Routine Load)、Hive / Iceberg / Hudi、JDBC 兼容数据库 | 统一通过 Catalog 机制管理 |
| 查询方式 | SELECT * FROM external_table; | 语法与本地表一致 |
| 适用场景 | 实时查看业务库数据、联邦查询 Hive 数仓、流式数据接入 | 避免频繁全表扫描外部大表 |
| 优势 | 无需导入即可查询、实时性高、减少数据冗余 | — |
9.2 MySQL 外部表配置与查询
| 操作 | 语法/配置 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建 Catalog | CREATE EXTERNAL CATALOG mysql_catalog PROPERTIES (...); | 定义 MySQL 数据源连接 | 见下方示例 | 支持批量映射多个表。 |
| 查询外部表 | SELECT * FROM mysql_cat.table_name; | 查询 MySQL 表数据 | SELECT * FROM mysql_cat.user_info WHERE id = 1001; | 支持 WHERE 下推,减少网络传输。 |
| 查看 Catalog | SHOW CATALOGS; 或 SHOW TABLES FROM mysql_catalog; | 列出所有 Catalog 或表 | SHOW TABLES FROM mysql_cat; | 确认表是否成功加载。 |
| 谓词下推 | 自动将 WHERE 条件下推到 MySQL 执行 | 提升查询效率 | WHERE create_time > '2025-01-01' → 在 MySQL 端过滤 | 不支持复杂函数下推。 |
| 性能建议 | 避免全表扫描;使用索引列过滤;控制返回字段 | 减少对源库压力 | 可结合物化视图缓存热点数据。 | |
创建 MySQL Catalog 示例:
CREATE EXTERNAL CATALOG mysql_cat
PROPERTIES (
"type" = "mysql",
"mysql.host" = "192.168.1.10",
"mysql.port" = "3306",
"mysql.user" = "root",
"mysql.password" = "123456",
"database" = "test_db"
);
9.3 Kafka 与 Routine Load 集成
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建 Routine Load | CREATE ROUTINE LOAD db.job_name ON tbl_name FROM KAFKA (...); | 从 Kafka 持续消费数据并导入 Doris | 见下方示例 | 支持 Exactly-Once 语义。 |
| 查看任务状态 | SHOW ROUTINE LOAD FOR job_name; | 监控消费进度、错误日志 | SHOW ROUTINE LOAD FOR kafka_job; | 关注 CurrentTaskStatus、DataProcessed。 |
| 暂停/启动任务 | PAUSE/RESUME ROUTINE LOAD FOR job_name; | 控制导入流程 | PAUSE ROUTINE LOAD FOR kafka_job; | 维护时可暂停。 |
| 错误处理 | 设置 max_error_number | 容忍部分数据错误 | PROPERTIES ("max_error_number" = "1000") | 超过阈值任务会暂停。 |
| 数据格式 | 支持 CSV、JSON、AVRO、Parquet | 灵活解析 Kafka 消息 | PROPERTIES ("format" = "json") | JSON 需配置 json_root 或 jsonpaths。 |
| 位点管理 | 自动提交消费位点(offset) | 保证不丢不重 | — | 停止任务后重新启动会从上次位点继续。 |
创建 Routine Load 示例:
CREATE ROUTINE LOAD example_db.kafka_job ON user_log
COLUMNS TERMINATED BY ",",
COLUMNS (user_id, event_type, ts),
PROPERTIES ("desired_concurrent_number"="1"),
FROM KAFKA (
"kafka_broker_list" = "broker1:9092,broker2:9092",
"kafka_topic" = "doris_log",
"kafka_partitions" = "0,1,2",
"kafka_offsets" = "OFFSET_BEGINNING"
);
9.4 Hive / Iceberg / Hudi 外部表接入
| 格式 | 配置方式 | 用途 | 注意事项 |
|---|
| Hive 外部表 | 创建 Hive Catalog,连接 Hive Metastore | 查询 Hive 表数据 | 见下方示例 |
| Iceberg 外部表 | 创建 Iceberg Catalog,指定 Metastore 或 File-based | 查询 Iceberg 表 | 见下方示例 |
| Hudi 外部表 | 创建 Hudi Catalog,连接 Hive Metastore | 查询 Hudi MOR/COW 表 | 见下方示例 |
| 共同特性 | 支持分区裁剪、谓词下推、列式扫描优化 | 提升大数据查询效率 | 查询性能依赖 HDFS/S3 访问速度。 |
| 使用建议 | 避免频繁全表扫描;使用分区列过滤;结合 Colocate Join 加速关联分析 | — | 可通过物化视图预聚合结果。 |
Hive Catalog 示例:
CREATE EXTERNAL CATALOG hive_cat
PROPERTIES (
"type" = "hive",
"hive.metastore.uris" = "thrift://hms:9083"
);
Iceberg Catalog 示例:
CREATE EXTERNAL CATALOG iceberg_cat
PROPERTIES (
"type" = "iceberg",
"iceberg.catalog.type" = "hive",
"iceberg.catalog.uri" = "thrift://hms:9083"
);
Hudi Catalog 示例:
CREATE EXTERNAL CATALOG hudi_cat
PROPERTIES (
"type" = "hudi",
"hive.metastore.uris" = "thrift://hms:9083"
);
9.5 JDBC Catalog 使用
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建 JDBC Catalog | CREATE EXTERNAL CATALOG jdbc_cat PROPERTIES (...); | 接入任意 JDBC 兼容数据库 | 见下方示例 | 需上传 JDBC 驱动到 FE lib 目录。 |
| 查询外部数据 | SELECT * FROM jdbc_cat.schema.table; | 执行远程查询 | SELECT * FROM pg_catalog.public.users WHERE status = 1; | 支持标准 SQL 语法。 |
| 驱动管理 | 手动上传 .jar 文件至 fe/lib/ | 加载数据库驱动 | wget https://repo1.maven.org/.../postgresql-42.5.0.jar -P fe/lib/ | 重启 FE 生效。 |
| 性能限制 | 网络延迟高,不适合大数据量扫描 | 适用于维表关联、小表查询 | 建议用于 Dimension 表而非 Fact 表。 | |
| 安全配置 | 支持 SSL 连接参数 | 加密传输 | 在 jdbc.url 中添加 ?ssl=true&... | 需数据库端支持 SSL。 |
创建 JDBC Catalog 示例:
CREATE EXTERNAL CATALOG pg_catalog
PROPERTIES (
"type" = "jdbc",
"jdbc.url" = "jdbc:postgresql://192.168.1.10:5432/test",
"jdbc.user" = "user",
"jdbc.password" = "pass",
"jdbc.driver_url" = "postgresql-42.5.0.jar",
"jdbc.driver_class" = "org.postgresql.Driver"
);
第十章:最佳实践与常见问题
10.1 表设计最佳实践
| 设计项 | 推荐做法 | 说明 | 注意事项 |
|---|
| 数据模型选择 | 明细数据 → Duplicate;指标聚合 → Aggregate;主键更新 → Unique | 根据业务需求选择 | 错误模型导致无法更新或查询慢。 |
| 分区设计 | 按时间分区(如 dt DATE),粒度按数据量定(日/小时) | 便于生命周期管理和查询剪枝 | 分区数不宜过多(<1000)。 |
| 分桶设计 | 选择高基数列(如 user_id),桶数 = BE 数 × (1~10) | 避免数据倾斜,提升并行度 | 建议总桶数在 10~100 倍 BE 数之间。 |
| 排序列(KEY) | 将高频过滤、Group By、Join 列放在前面 | 提升前缀索引命中率 | 前 36 字节用于索引。 |
| 属性配置 | 设置 replication_num=3,启用 Bloom Filter | 提升可用性和查询性能 | 生产环境必须多副本。 |
| 建表模板 | 使用 SHOW CREATE TABLE 导出标准建表语句 | 统一团队建表规范 | 避免随意建表导致管理混乱。 |
10.2 导入性能优化建议
| 优化方向 | 建议措施 | 说明 |
|---|
| 导入方式选择 | 实时小批量 → Stream Load;离线大批量 → Broker Load;流式数据 → Routine Load | 匹配场景选择最优方式 |
| 并发控制 | 提高并发任务数和单任务并发度 | desired_concurrent_number 控制 Routine Load 并发 |
| 批量大小 | Stream Load 单次 100MB~1GB;Broker Load 分片导入 | 避免过小(开销大)或过大(超时) |
| 数据格式 | 使用列式格式(Parquet/ORC)替代 CSV | 减少网络传输和解析开销 |
| 错误容忍 | 设置 max_filter_ratio > 0 | 容忍少量脏数据,避免任务失败 |
| 资源隔离 | 为导入任务分配独立线程池或队列 | 避免影响查询性能 |
| 监控告警 | 监控导入延迟、失败率、吞吐量 | 及时发现异常 |
10.3 查询性能调优案例
| 问题现象 | 可能原因 | 解决方案 |
|---|
| 查询慢(>10s) | 未命中分区/分桶;全表扫描;Join 倾斜 | 检查 WHERE 是否包含分区列;使用 EXPLAIN 分析执行计划;改写为 Colocate Join |
| 内存溢出(OOM) | 大表 Join;大量去重(COUNT DISTINCT);排序数据量大 | 增加 BE 内存;使用 NDV() 替代 COUNT(DISTINCT);启用 mem_limit 限制单查询内存 |
| 查询延迟高 | 集群负载高;磁盘 I/O 瓶颈;网络延迟 | 查看 BE CPU/Disk 使用率;升级 SSD;优化网络环境 |
| 结果不一致 | 导入未完成;缓存未刷新 | 等待导入完成;使用 REFRESH MATERIALIZED VIEW |
| 无法命中 Rollup | 查询列不匹配;聚合方式不同 | 检查 Rollup 定义;确保查询可被覆盖 |
10.4 常见错误码与解决方案
| 错误码/信息 | 原因 | 解决方案 |
|---|
errCode = 2, detailMessage = TabletNotFound | Tablet 未找到(副本缺失) | 检查 BE 是否宕机,等待自动恢复或手动修复 |
errCode = 410, detailMessage = Failed to send batch | BE 写入失败 | 检查 BE 存储空间、网络、日志 |
Max filter ratio exceeded | 数据质量差,错误行超过阈值 | 清洗数据或提高 max_filter_ratio |
Transaction already committed | 重复提交相同 Label | 更换导入 Label |
Memory limit exceeded | 查询内存超限 | 优化 SQL 或调整 exec_mem_limit |
Can't find partition | 分区不存在或已删除 | 检查分区名、时间范围 |
User has no access | 权限不足 | 使用 GRANT 授予权限 |
Broker does not exist | Broker 未部署或宕机 | 检查 Broker 服务状态 |
10.5 集群备份与恢复策略
| 策略 | 方法 | 说明 | 注意事项 |
|---|
| 元数据备份 | 备份 FE 元数据目录(fe/palo-meta/) | 包含表结构、用户、权限等 | 停止 FE 后备份,或使用 ADMIN REPAIR 命令 |
| 数据备份 | 使用 EXPORT 命令导出数据;复制 HDFS/S3 上的 Tablet 数据 | 实现全量或增量备份 | EXPORT 支持 Parquet/CSV 格式 |
| 快照备份 | ALTER TABLE tbl1 SNAPSHOT ... | 创建数据快照 | Doris 2.0+ 支持 |
| 恢复方式 | 重建集群 + 导入备份数据;使用 RESTORE 命令(未来支持) | — | 当前主要依赖重导 |
| 定期任务 | 使用脚本 + cron 定时备份 | 自动化运维 | 建议每日备份元数据,每周全量数据 |
| 灾备方案 | 搭建异地 Doris 集群,通过 Routine Load 或 Kafka 同步 | 实现高可用 | 延迟取决于同步机制 |