# StarRocks/Doris 深度实践

StarRocks/Doris 深度实践:极速全场景 OLAP 引擎

一、为什么选择 StarRocks/Doris?

1.1 OLAP 引擎选型对比

引擎 优势 劣势 适用场景
ClickHouse 单表查询极快 Join 能力弱、运维复杂 日志分析、单表聚合
Presto/Trino 联邦查询强 无索引、延迟高 即席查询、跨源查询
Elasticsearch 全文搜索强 聚合性能弱 搜索、日志检索
StarRocks/Doris Join 能力强、运维简单 生态相对新 多维分析、实时数仓

1.2 StarRocks vs Doris

关系: StarRocks fork 自 Doris,两者同源但已分化

特性 Doris StarRocks
Join 优化 Hash Join CBO + 向量化 Join
物化视图 单表聚合 多表 Join 物化
联邦查询 支持 支持(更强)
写入性能 较高 更高(向量化)
社区活跃度 更高
企业采用 百度、小米 美团、字节、网易

选型建议:

  • 新项目优先 StarRocks(性能更优、社区更活跃)
  • 已有 Doris 集群可继续用(兼容性好)
  • 本文以 StarRocks 为主,Doris 差异会标注

1.3 核心优势

复制代码
StarRocks = MySQL 协议 + MPP 架构 + 向量化引擎

核心优势:
1. 极速查询 - 向量化执行,比 Doris 快 3-10 倍
2. 灵活更新 - 支持 Upsert、部分更新
3. 实时写入 - 微批次提交,秒级可见
4. 联邦查询 - 一张 SQL 查遍 Hive/Iceberg/MySQL/ES
5. 运维简单 - 无外部依赖,FE+BE 即可运行

量化对比(某电商实测):

查询类型 Doris StarRocks ClickHouse
单表聚合 1.2s 0.4s 0.3s
多表 Join 5.8s 1.2s 8.5s
点查 50ms 30ms 20ms
并发查询 100 QPS 300 QPS 150 QPS

二、架构原理

2.1 整体架构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        客户端层                                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐        │
│  │  MySQL   │  │  JDBC    │  │  Spark   │  │  Flink   │        │
│  │  Client  │  │  Driver  │  │  Connector│ │  Connector│        │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘        │
└─────────────────────────────────────────────────────────────────┘
                              ↓ (MySQL 协议)
┌─────────────────────────────────────────────────────────────────┐
│                     Frontend (FE)                                │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                      │
│  │  解析器   │  │  优化器   │  │  调度器   │                      │
│  │ (Parser) │  │ (CBO)    │  │ (Planner)│                      │
│  └──────────┘  └──────────┘  └──────────┘                      │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              元数据管理 (MetaService)                      │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
                              ↓ (RPC)
┌─────────────────────────────────────────────────────────────────┐
│                     Backend (BE)                                 │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              查询执行引擎 (Execution Engine)                │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐                │   │
│  │  │ 向量化   │  │ 管道执行  │  │ 并行计算  │                │   │
│  │  └──────────┘  └──────────┘  └──────────┘                │   │
│  └──────────────────────────────────────────────────────────┘   │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │  存储引擎    │  │  索引管理    │  │  缓存管理    │             │
│  │  (Column)   │  │ (Bitmap 等)  │  │  (Page)     │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
└─────────────────────────────────────────────────────────────────┘

2.2 数据模型

三种数据模型:

复制代码
1. Aggregate 模型(聚合模型)
   - 主键相同的行自动聚合
   - 适用:预聚合场景(UV、PV、Sum)
   
   示例:
   CREATE TABLE ads_uv_daily (
       date DATE,
       user_id BIGINT,
       pv SUM,
       uv BITMAP_UNION
   )
   AGGREGATE KEY(date, user_id);

2. Unique 模型(主键模型)
   - 主键唯一,支持 Upsert
   - 适用:需要更新删除的场景
   
   示例:
   CREATE TABLE dwd_order_detail (
       order_id BIGINT,
       user_id BIGINT,
       amount DECIMAL(18,2),
       status INT
   )
   UNIQUE KEY(order_id);

3. Duplicate 模型(明细模型)
   - 保留所有明细数据
   - 适用:日志、流水等无需去重场景
   
   示例:
   CREATE TABLE ods_click_log (
       event_time DATETIME,
       user_id BIGINT,
       page_url STRING
   )
   DUPLICATE KEY(event_time, user_id);

2.3 分区与分桶

分区(Partition):

复制代码
- 按范围分区(RANGE)
- 通常按时间(天/月)
- 便于数据生命周期管理

示例:
PARTITION BY RANGE(event_time) (
    PARTITION p20260401 VALUES LESS THAN ('2026-04-02'),
    PARTITION p20260402 VALUES LESS THAN ('2026-04-03'),
    PARTITION p20260403 VALUES LESS THAN ('2026-04-04')
)

分桶(Bucket):

复制代码
- 按 Hash 分桶
- 决定并行度
- 影响查询性能

分桶数计算:
- 单表数据量 / 1GB = 分桶数
- 或:BE 节点数 * CPU 核数 * (1-3)

示例:
DISTRIBUTED BY HASH(order_id) BUCKETS 32

三、实战操作

3.1 部署配置

FE 配置(fe.conf):

bash 复制代码
# FE 节点配置
priority_networks = 192.168.1.0/24
edit_log_port = 9010
http_port = 8030
query_port = 9030
rpc_port = 9020

BE 配置(be.conf):

bash 复制代码
# BE 节点配置
priority_networks = 192.168.1.0/24
be_port = 9060
brpc_port = 8040
webserver_port = 8040
heartbeat_service_port = 9050

# 存储路径
storage_root_path = /data/starrocks/storage

# 内存配置
mem_limit = 80%

# 查询配置
disable_storage_page_cache = false

部署命令:

bash 复制代码
# 启动 FE
./fe/bin/start_fe.sh --daemon

# 添加 FE 节点(MySQL 客户端)
mysql -h 127.0.0.1 -P 9030 -u root
ALTER SYSTEM ADD FOLLOWER "fe-2:9010";
ALTER SYSTEM ADD FOLLOWER "fe-3:9010";

# 启动 BE
./be/bin/start_be.sh --daemon

# 添加 BE 节点
ALTER SYSTEM ADD BACKEND "be-1:9050";
ALTER SYSTEM ADD BACKEND "be-2:9050";
ALTER SYSTEM ADD BACKEND "be-3:9050";

3.2 表设计

实时数仓表设计:

sql 复制代码
-- ODS 层(明细数据)
CREATE TABLE IF NOT EXISTS ods_order_info (
    order_id BIGINT COMMENT '订单 ID',
    user_id BIGINT COMMENT '用户 ID',
    amount DECIMAL(18,2) COMMENT '订单金额',
    status TINYINT COMMENT '订单状态',
    create_time DATETIME COMMENT '创建时间',
    update_time DATETIME COMMENT '更新时间'
)
DUPLICATE KEY(order_id, create_time)
PARTITION BY RANGE(create_time) (
    PARTITION p20260401 VALUES LESS THAN ('2026-04-02'),
    PARTITION p20260402 VALUES LESS THAN ('2026-04-03'),
    PARTITION p20260403 VALUES LESS THAN ('2026-04-04')
)
DISTRIBUTED BY HASH(order_id) BUCKETS 32
PROPERTIES (
    "replication_num" = "3",
    "storage_format" = "DEFAULT",
    "light_schema_change" = "true"
);

-- DWD 层(明细事实表)
CREATE TABLE IF NOT EXISTS dwd_order_detail (
    order_id BIGINT COMMENT '订单 ID',
    user_id BIGINT COMMENT '用户 ID',
    amount DECIMAL(18,2) COMMENT '订单金额',
    pay_amount DECIMAL(18,2) COMMENT '实付金额',
    category_id BIGINT COMMENT '品类 ID',
    brand_id BIGINT COMMENT '品牌 ID',
    create_time DATETIME COMMENT '创建时间'
)
UNIQUE KEY(order_id)
PARTITION BY RANGE(create_time) (
    PARTITION p20260401 VALUES LESS THAN ('2026-04-02'),
    PARTITION p20260402 VALUES LESS THAN ('2026-04-03')
)
DISTRIBUTED BY HASH(order_id) BUCKETS 32
PROPERTIES (
    "replication_num" = "3",
    "enable_mow_light_delete" = "true"
);

-- DWS 层(轻度聚合)
CREATE TABLE IF NOT EXISTS dws_order_daily (
    dt DATE COMMENT '日期',
    category_id BIGINT COMMENT '品类 ID',
    order_count BIGINT SUM COMMENT '订单数',
    gmv DECIMAL(20,2) SUM COMMENT '交易额',
    buyer_count BIGINT BITMAP_UNION COMMENT '购买人数'
)
AGGREGATE KEY(dt, category_id)
DISTRIBUTED BY HASH(category_id) BUCKETS 16
PROPERTIES (
    "replication_num" = "3"
);

-- ADS 层(应用数据)
CREATE TABLE IF NOT EXISTS ads_category_ranking (
    dt DATE COMMENT '日期',
    category_name STRING COMMENT '品类名称',
    gmv DECIMAL(20,2) COMMENT '交易额',
    gmv_rank BIGINT COMMENT '排名',
    mom_growth DECIMAL(10,4) COMMENT '环比增长'
)
DUPLICATE KEY(dt)
DISTRIBUTED BY HASH(dt) BUCKETS 10
PROPERTIES (
    "replication_num" = "3"
);

3.3 数据导入

Stream Load(实时导入):

bash 复制代码
# 导入 JSON 数据
curl --location-trusted -u user:password \
    -T order_data.json \
    -H "label:label_20260409_001" \
    -H "column_separator: ," \
    -H "columns: order_id,user_id,amount,status,create_time" \
    http://be-1:8040/api/ods_order_info/_stream_load

# 导入 CSV 数据
curl --location-trusted -u user:password \
    -T order_data.csv \
    -H "label:label_20260409_002" \
    -H "column_separator: ," \
    -H "format: csv" \
    http://be-1:8040/api/ods_order_info/_stream_load

Routine Load(Kafka 实时导入):

sql 复制代码
-- 创建 Kafka 导入任务
CREATE ROUTINE LOAD ods_order_info_load ON ods_order_info
COLUMNS TERMINATED BY ","
COLUMNS (order_id, user_id, amount, status, create_time)
WHERE status != -1
PROPERTIES (
    "desired_concurrent_number" = "3",
    "max_batch_interval" = "10",
    "max_batch_rows" = "100000"
)
FROM KAFKA (
    "kafka_broker1" = "kafka-1:9092",
    "kafka_broker2" = "kafka-2:9092",
    "kafka_broker3" = "kafka-3:9092",
    "kafka_topic" = "ods.order.events",
    "kafka_partitions" = "0,1,2,3",
    "property.client.id" = "starrocks_ods_order",
    "property.group.id" = "starrocks_ods_order_group",
    "property.auto.offset.reset" = "earliest"
);

-- 查看导入状态
SHOW LOAD FROM ods_order_info_load;

-- 暂停/恢复导入
STOP ROUTINE LOAD FOR ods_order_info_load;
RESUME ROUTINE LOAD FOR ods_order_info_load;

Insert Into(ETL 写入):

sql 复制代码
-- ODS → DWD
INSERT INTO dwd_order_detail
SELECT 
    order_id,
    user_id,
    amount,
    amount - discount AS pay_amount,
    category_id,
    brand_id,
    create_time
FROM ods_order_info
WHERE dt = '2026-04-08';

-- DWD → DWS(聚合)
INSERT INTO dws_order_daily
SELECT 
    DATE(create_time) AS dt,
    category_id,
    COUNT(*) AS order_count,
    SUM(amount) AS gmv,
    BITMAP_UNION(BITMAP_BUILD(user_id)) AS buyer_count
FROM dwd_order_detail
WHERE DATE(create_time) = '2026-04-08'
GROUP BY DATE(create_time), category_id;

Broker Load(HDFS/S3 导入):

sql 复制代码
-- 从 HDFS 导入
LOAD LABEL ods_order_info_load_20260409
(
    DATA INFILE("hdfs://namenode:8020/data/ods/order_info/*.parquet")
    INTO TABLE ods_order_info
    FORMAT AS PARQUET
)
WITH BROKER hdfs_broker
(
    "username" = "hdfs_user",
    "password" = "hdfs_password"
)
PROPERTIES
(
    "timeout" = "3600",
    "max_filter_ratio" = "0.01"
);

3.4 物化视图

同步物化视图:

sql 复制代码
-- 创建物化视图(自动刷新)
CREATE MATERIALIZED VIEW mv_category_daily AS
SELECT 
    DATE(create_time) AS dt,
    category_id,
    COUNT(*) AS order_count,
    SUM(amount) AS gmv,
    COUNT(DISTINCT user_id) AS buyer_count
FROM dwd_order_detail
GROUP BY DATE(create_time), category_id;

-- 查询自动路由到物化视图
-- 无需修改 SQL,优化器自动选择
SELECT 
    DATE(create_time) AS dt,
    category_id,
    COUNT(*) AS order_count,
    SUM(amount) AS gmv
FROM dwd_order_detail
WHERE DATE(create_time) >= '2026-04-01'
GROUP BY DATE(create_time), category_id;

异步物化视图:

sql 复制代码
-- 创建异步物化视图
CREATE MATERIALIZED VIEW mv_order_summary
REFRESH ASYNC START('2026-04-09 00:00:00') EVERY (INTERVAL 1 HOUR)
PROPERTIES (
    "replication_num" = "3"
)
AS
SELECT 
    DATE_TRUNC('hour', create_time) AS hour,
    status,
    COUNT(*) AS order_count,
    SUM(amount) AS gmv
FROM dwd_order_detail
GROUP BY DATE_TRUNC('hour', create_time), status;

-- 手动刷新
REFRESH MATERIALIZED VIEW mv_order_summary;

-- 查看刷新状态
SHOW ALTER TABLE MATERIALIZED VIEW mv_order_summary;

3.5 联邦查询

创建 External Catalog:

sql 复制代码
-- Hive Catalog
CREATE EXTERNAL CATALOG hive_catalog
PROPERTIES (
    "type" = "hive",
    "hive.metastore.uris" = "thrift://hive-metastore:9083"
);

-- Iceberg Catalog
CREATE EXTERNAL CATALOG iceberg_catalog
PROPERTIES (
    "type" = "iceberg",
    "iceberg.catalog.type" = "hive",
    "hive.metastore.uris" = "thrift://hive-metastore:9083"
);

-- MySQL Catalog
CREATE EXTERNAL CATALOG mysql_catalog
PROPERTIES (
    "type" = "jdbc",
    "jdbc.user" = "root",
    "jdbc.password" = "password",
    "jdbc.url" = "jdbc:mysql://mysql:3306/test",
    "jdbc.driver.url" = "jdbc:mysql://mysql:3306",
    "jdbc.driver.class" = "com.mysql.cj.jdbc.Driver"
);

跨源查询:

sql 复制代码
-- 查询 Hive 表
SELECT * FROM hive_catalog.dw.order_detail LIMIT 100;

-- 查询 Iceberg 表
SELECT * FROM iceberg_catalog.prod.order_fact LIMIT 100;

-- 跨源 Join(StarRocks + Hive + MySQL)
SELECT 
    s.order_id,
    s.amount,
    u.user_name,
    p.product_name
FROM dwd_order_detail s
JOIN hive_catalog.dim.user_dim u ON s.user_id = u.user_id
JOIN mysql_catalog.product p ON s.product_id = p.id
WHERE s.dt = '2026-04-08';

四、性能优化

4.1 索引优化

前缀索引:

sql 复制代码
-- 自动创建(Duplicate/Unique 模型的前 N 列)
-- 无需手动创建,默认前 36 字节

ZoneMap 索引:

sql 复制代码
-- 自动创建,每列都有
-- 记录每列的 Min/Max/Null Count
-- 用于谓词下推

Bitmap 索引:

sql 复制代码
-- 手动创建(高基数字段)
CREATE INDEX idx_user_id ON dwd_order_detail USING BITMAP(user_id);

-- 适用于:
-- - 等值查询
-- - IN 查询
-- - 去重计数

倒排索引:

sql 复制代码
-- 手动创建(文本字段)
CREATE INDEX idx_product_name ON dwd_order_detail USING INVERTED(product_name);

-- 适用于:
-- - 模糊查询
-- - 全文检索

4.2 SQL 优化

执行计划分析:

sql 复制代码
-- 查看执行计划
EXPLAIN SELECT * FROM dwd_order_detail WHERE order_id = 123456;

-- 查看详细执行计划(含成本)
EXPLAIN VERBOSE SELECT * FROM dwd_order_detail WHERE order_id = 123456;

-- 查看 Profile(查询后)
SHOW PROFILE;

常见优化技巧:

sql 复制代码
-- 1. 避免 SELECT *
SELECT order_id, user_id, amount FROM dwd_order_detail;  -- 推荐
SELECT * FROM dwd_order_detail;  -- 不推荐

-- 2. 利用分区裁剪
SELECT * FROM dwd_order_detail 
WHERE create_time >= '2026-04-08';  -- 会裁剪分区

-- 3. 利用分桶裁剪
SELECT * FROM dwd_order_detail 
WHERE order_id = 123456;  -- 只查一个分桶

-- 4. 避免函数操作导致索引失效
WHERE DATE(create_time) = '2026-04-08';  -- 索引失效
WHERE create_time >= '2026-04-08' AND create_time < '2026-04-09';  -- 索引生效

-- 5. 大表 Join 小表,小表广播
SELECT /*+ BROADCAST(u) */ * 
FROM dwd_order_detail o
JOIN dim_user u ON o.user_id = u.user_id;

4.3 参数调优

查询参数:

sql 复制代码
-- 设置并发度
SET SESSION parallel_fragment_exec_instance_num = 4;

-- 设置内存限制
SET SESSION exec_mem_limit = 4G;

-- 设置超时时间
SET SESSION query_timeout = 300;

-- 启用 CBO
SET SESSION enable_cbo = true;

-- 启用向量化
SET SESSION enable_vectorized_engine = true;

BE 参数调优:

bash 复制代码
# be.conf

# 内存限制
mem_limit = 80%

# 查询并发度
be_threads_per_query_per_fragment = 4

# 存储页缓存
disable_storage_page_cache = false
storage_page_cache_limit = 20GB

# 写入并发
write_thread_pool_size = 48

五、生产环境落地案例

5.1 案例背景

公司: 某电商平台
规模: 日订单 300 万 +,日增数据 800GB
团队: 数据团队 45 人

建设前痛点:

  • ClickHouse Join 能力弱,多维分析困难
  • Presto 查询延迟高(平均 5-10 秒)
  • 运维复杂(多套系统)
  • 无法支持实时更新

5.2 建设方案

阶段一:实时数仓(2 个月)

复制代码
- StarRocks 集群部署(3 FE + 6 BE)
- Kafka → StarRocks 实时导入
- 核心表迁移(20 张表)

阶段二:多维分析(2 个月)

复制代码
- 物化视图建设
- 联邦查询整合 Hive/Iceberg
- 报表迁移

阶段三:优化治理(持续)

复制代码
- 性能调优
- 资源隔离
- 监控告警

5.3 建设效果

指标 建设前 建设后 提升
查询延迟 5-10s 0.5-2s 80% ↓
并发能力 50 QPS 300 QPS 6 倍 ↑
运维成本 3 套系统 1 套系统 67% ↓
数据可见性 分钟级 秒级 90% ↓

六、总结

核心要点

  1. StarRocks 是全场景 OLAP - 单表、Join、聚合都强
  2. 数据模型选择关键 - Aggregate/Unique/Duplicate 按需选择
  3. 分区分桶影响性能 - 合理设计决定查询效率
  4. 物化视图是利器 - 自动加速查询
  5. 联邦查询整合数据 - 一张 SQL 查遍所有数据源

最佳实践

yaml 复制代码
表设计:
  - 按时间分区(天/小时)
  - 分桶数 = BE 节点数 * CPU * (1-3)
  - 高基数字段放前面

数据导入:
  - 实时:Routine Load(Kafka)
  - 批量:Stream Load / Broker Load
  - ETL: INSERT INTO

查询优化:
  - 避免 SELECT *
  - 利用分区/分桶裁剪
  - 物化视图加速

运维管理:
  - 监控 BE 内存使用
  - 定期 Compaction
  - 日志定期清理

附录

A. 版本兼容性

StarRocks 版本 MySQL 协议 Flink Connector Spark Connector
2.x 5.7 1.13-1.15 3.1-3.2
3.x 8.0 1.15-1.17 3.2-3.4

B. 推荐阅读


下一篇: 《流批一体架构落地》

上一篇: 《Iceberg 数据湖实战》

系列目录: 新技术实战系列

相关推荐
千月落2 天前
部署Doris存算一体集群
doris
何中应5 天前
Doris部署&连接
大数据·数据库·时序数据库·doris
喵了几个咪14 天前
Apache Doris 4.x 在量化交易中的完整应用实践
ai·doris·量化交易
piepis15 天前
Doris 快速写入原理
doris
AllData公司负责人24 天前
高效同步!离线开发平台(DolphinScheduler) 实现Apache IotDB物联网数据同步到 Doris
apache·doris·iotdb
jasnet_u1 个月前
Doris的集群搭建(3FE+3BE)
doris·mpp
家有娇妻张兔兔1 个月前
Apache Doris 副本故障排查与修复实战指南
apache·doris·时序库
秦拿希2 个月前
【doris】doris部署
doris
linweidong2 个月前
别让老板等:千人并发下的实时大屏极致性能优化实录
jmeter·clickhouse·性能优化·sentinel·doris·物化视图·离线数仓