我们用StarRocks做数据分析,最开始查询很慢,经过一系列优化,性能提升了10倍。

StarRocks是一个高性能的分析型数据库,主打亚秒级查询。但如果用不好,性能也会很差。本文分享StarRocks性能优化的实战经验,包括表设计优化、分区分桶优化、数据模型选择、索引优化、SQL优化、资源配置、监控调优,以及踩过的坑和经验总结。

一、背景

1. 为什么选StarRocks

我们之前用的是ClickHouse,性能不错,但有几个问题:

  • 多表关联性能差
  • 不支持标准SQL,学习成本高
  • 并发能力弱
  • 运维复杂

后来调研了StarRocks,发现它:

  • 兼容MySQL协议,学习成本低
  • 多表关联性能好(CBO优化器)
  • 并发能力强
  • 支持实时更新
  • 运维相对简单

于是,我们把数据分析平台迁移到了StarRocks。

2. 遇到的问题

迁移之后,最开始性能很差:

  • 简单查询要几秒
  • 复杂查询要几十秒甚至几分钟
  • 并发上不去,几个查询就卡
  • 数据导入慢
  • 资源占用高

我们花了一个月时间优化,性能提升了10倍。本文分享优化过程。

二、表设计优化

表设计,是StarRocks性能优化的基础。表设计不好,后面怎么优化都没用。

1. 数据模型选择

StarRocks有三种数据模型:

  • 明细模型(Duplicate Key):保留所有明细数据,适合原始数据存储
  • 聚合模型(Aggregate Key):按Key聚合,适合预聚合场景
  • 更新模型(Unique Key):按Key更新,适合需要更新的场景

选择建议:

  • 原始数据、日志数据:用明细模型
  • 汇总数据、报表数据:用聚合模型
  • 需要更新的数据:用更新模型

我们最开始所有表都用明细模型,查询的时候再聚合,性能很差。后来把常用的汇总表改成聚合模型,查询性能提升了3-5倍。

2. 排序键(Sort Key)

StarRocks的数据是按排序键排序存储的,排序键的选择很重要。

排序键的原则:

  • 把常用的过滤条件字段放在前面
  • 把等值查询的字段放在前面
  • 把高基数的字段放在前面
  • 排序键的前3个字段最重要

比如,我们有一张订单表,常用的过滤条件是日期和用户ID。我们把排序键设为(dt, userid, orderid),查询的时候按日期和用户ID过滤,性能很好。

如果排序键设错了,比如把order_id放在前面,查询的时候按日期过滤,就会全表扫描,性能很差。

3. 字段类型选择

字段类型,对性能也有影响。

  • 尽量用小的数据类型:能用TINYINT就不用INT,能用INT就不用BIGINT
  • 字符串类型:VARCHAR比STRING好,尽量控制长度
  • 日期类型:用DATE或DATETIME,不要用字符串
  • 避免用FLOAT/DOUBLE做关联键,精度问题

我们有一张表,把日期存成了VARCHAR,查询的时候做类型转换,性能很差。改成DATE类型之后,性能提升了2倍。

三、分区分桶优化

1. 分区(Partition)

分区是StarRocks性能优化的重要手段。

分区的原则:

  • 按时间分区:最常用,按天或按月分区
  • 分区数量:单表分区数建议不超过1000
  • 分区大小:每个分区建议100GB以内
  • 动态分区:可以配置自动创建和删除分区

我们的表都是按天分区,查询的时候指定日期,只扫描对应分区,性能很好。

如果不分区,查询就会全表扫描,性能很差。

2. 分桶(Bucket)

分桶决定了数据在节点之间的分布。

分桶的原则:

  • 分桶列:选择高基数的列,如用户ID、订单ID
  • 分桶数量:根据数据量和节点数确定
  • 每个分桶的大小:建议1-10GB
  • 分桶数量一旦确定,不能修改

分桶数量的经验公式:

  • 数据量 / 每个分桶大小 = 分桶数量
  • 分桶数量应该是节点数的整数倍

我们有一张表,最开始只分了4个桶,数据量很大,每个桶几十GB,查询很慢。后来改成32个桶,每个桶几GB,查询性能提升了3倍。

3. 动态分区

StarRocks支持动态分区,可以自动创建和删除分区。

配置示例:

PROPERTIES (
  "dynamic_partition.enable" = "true",
  "dynamic_partition.time_unit" = "DAY",
  "dynamic_partition.start" = "-30",
  "dynamic_partition.end" = "3",
  "dynamic_partition.prefix" = "p",
  "dynamic_partition.buckets" = "32"
);

这样,StarRocks会自动创建未来3天的分区,自动删除30天前的分区。不用手动管理分区了。

四、索引优化

1. 前缀索引

StarRocks默认有前缀索引,基于排序键的前36个字节。

前缀索引的原理:

  • 数据按排序键排序
  • 每1024行数据,建立一个前缀索引项
  • 查询的时候,先用前缀索引定位到大概位置,再精确查找

用好前缀索引的关键:

  • 排序键的前几个字段,要是常用的过滤条件
  • 等值查询的字段,尽量放在排序键前面
  • 避免在排序键前面用范围查询(会导致后面的字段用不上前缀索引)

2. Bitmap索引

对于低基数的列(如性别、状态、类型),可以建Bitmap索引。

CREATE INDEX idx_status ON table_name(status) USING BITMAP;

Bitmap索引适合:

  • 低基数列(几个到几十个不同值)
  • 常用的过滤条件
  • 多条件组合查询

我们有一张表,status字段只有几个值,建了Bitmap索引之后,按status过滤的查询性能提升了5倍。

3. Bloom Filter索引

对于高基数的列(如用户ID、订单ID),可以建Bloom Filter索引。

PROPERTIES (
  "bloom_filter_columns" = "user_id, order_id"
);

Bloom Filter适合:

  • 高基数列
  • 等值查询
  • 非排序键的列

我们有一张表,userid不是排序键,但经常用userid做等值查询。建了Bloom Filter之后,查询性能提升了2倍。

五、SQL优化

1. 用EXPLAIN分析执行计划

SQL慢,第一步是用EXPLAIN看执行计划。

EXPLAIN SELECT * FROM orders WHERE dt = '2022-10-01' AND user_id = 123;

看执行计划,重点关注:

  • 扫描了多少分区
  • 扫描了多少行
  • 有没有用上索引
  • Join的顺序和方式
  • 有没有数据倾斜

2. 避免SELECT *

不要用SELECT *,只查需要的字段。

StarRocks是列式存储,只查需要的列,可以减少IO。

-- 不好
SELECT * FROM orders;

-- 好
SELECT order_id, user_id, amount FROM orders;

3. 过滤条件下推

尽量把过滤条件写在WHERE里,让StarRocks尽早过滤数据。

  • 分区裁剪:指定分区字段,只扫描需要的分区
  • 前缀索引:过滤条件用上排序键
  • Bitmap/Bloom Filter:过滤条件用上索引

4. Join优化

多表关联,是StarRocks的强项,但也要注意:

  • 小表在前,大表在后
  • 用等值关联,不要用不等值关联
  • 关联键尽量用整数类型
  • 避免大表关联大表
  • 可以用Broadcast Join(小表广播到所有节点)

StarRocks的CBO优化器会自动选择Join策略,但如果统计信息不准,可能选错。可以用ANALYZE TABLE更新统计信息。

5. 聚合优化

聚合查询,注意:

  • 尽量用聚合模型的表,预聚合数据
  • GROUP BY的字段,尽量用排序键
  • 避免在聚合函数里用复杂表达式
  • 可以用物化视图预计算常用聚合

6. 避免在WHERE里用函数

不要在WHERE里对字段用函数,会导致索引用不上。

-- 不好
SELECT * FROM orders WHERE DATE(create_time) = '2022-10-01';

-- 好
SELECT * FROM orders WHERE create_time >= '2022-10-01' AND create_time < '2022-10-02';

六、物化视图

物化视图,是StarRocks的一大利器。

1. 什么是物化视图

物化视图,就是把常用的查询结果预先计算好,存起来。查询的时候直接读物化视图,不用重新计算。

比如,我们经常按天统计销售额,可以建一个物化视图:

CREATE MATERIALIZED VIEW mv_daily_sales AS
SELECT dt, SUM(amount) as total_amount
FROM orders
GROUP BY dt;

查询的时候,StarRocks会自动路由到物化视图,性能提升很多。

2. 物化视图的适用场景

  • 常用的聚合查询
  • 多表关联的查询
  • 报表查询
  • 固定维度的统计

3. 注意事项

  • 物化视图会占用存储空间
  • 数据导入的时候,会同步更新物化视图,影响导入性能
  • 不要建太多物化视图,维护成本高
  • 定期检查物化视图是否被使用

我们建了几个常用报表的物化视图,报表查询性能提升了5-10倍。

七、资源配置优化

1. 节点配置

StarRocks的节点,分为FE(Frontend)和BE(Backend)。

  • FE:管理元数据,执行SQL解析和优化。建议3个节点,保证高可用。
  • BE:存储数据,执行查询。根据数据量和并发量确定节点数。

BE节点的配置建议:

  • CPU:16核以上
  • 内存:64GB以上
  • 磁盘:SSD,NVMe更好
  • 网络:万兆网卡

2. 内存配置

BE的内存配置很重要。

  • mem_limit:BE进程可用内存比例,建议80%
  • querymemlimit:单个查询的内存限制,根据查询大小调整
  • loadmemlimit:导入的内存限制

内存不够,查询会 spill 到磁盘,性能急剧下降。要保证内存充足。

3. 并发控制

StarRocks的并发控制:

  • queryqueueconcurrency_limit:查询队列的并发限制
  • queryqueuememusedpct_limit:内存使用比例限制
  • maxqueryretry_time:查询重试次数

根据服务器配置,合理设置并发数。并发太高,会导致资源争抢,性能反而下降。

4. 导入优化

数据导入的优化:

  • 用Stream Load或Broker Load
  • 批量导入,每次导入的数据量不要太小
  • 控制导入并发,避免影响查询
  • 合理设置导入的内存限制

我们最开始是一条条导入,性能很差。改成批量导入之后,导入性能提升了10倍。

八、监控和调优

1. 监控指标

StarRocks的监控,重点关注:

  • 查询延迟:P50、P95、P99
  • 查询并发:当前查询数
  • 导入延迟:导入的耗时
  • 存储使用:磁盘使用率
  • 内存使用:BE内存使用率
  • CPU使用:CPU使用率
  • 慢查询:超过阈值的查询

2. 慢查询分析

定期分析慢查询:

  • 开启慢查询日志
  • 每天分析慢查询
  • 对慢查询做优化
  • 优化后验证效果

我们建立了慢查询分析机制,每天花半小时分析慢查询,逐个优化,整体性能持续提升。

3. 统计信息更新

StarRocks的CBO优化器依赖统计信息。统计信息不准,优化器可能选错执行计划。

定期更新统计信息:

ANALYZE TABLE table_name;

建议:

  • 每天更新一次统计信息
  • 数据量大变化后,手动更新
  • 重点更新常用查询的表

九、踩过的坑

坑一:分桶数量不对

我们有一张表,分桶数量太少,数据倾斜严重,查询很慢。

后来重新建表,调整了分桶数量,查询性能提升了3倍。

教训:分桶数量要根据数据量确定,不能随便设。


坑二:排序键设错

我们有一张表,排序键设错了,常用的过滤字段不在排序键前面,查询全表扫描。

后来重新建表,调整了排序键,查询性能提升了5倍。

教训:排序键是StarRocks性能的关键,设之前要想清楚查询模式。


坑三:数据模型选错

我们有一张汇总表,最开始用了明细模型,查询的时候再聚合,性能很差。

改成聚合模型之后,查询性能提升了4倍。

教训:根据查询模式选择数据模型,汇总表用聚合模型。


坑四:并发太高

我们最开始把并发设得很高,结果查询互相争抢资源,整体性能很差。

后来降低了并发,反而整体吞吐量提升了。

教训:并发不是越高越好,要根据服务器配置合理设置。


坑五:统计信息不准

有一次,一个简单的查询突然变得很慢。查了半天,发现是统计信息过期了,优化器选错了执行计划。

更新统计信息之后,查询恢复正常。

教训:定期更新统计信息,数据变化大的时候要手动更新。

十、优化效果

经过一个月的优化,效果很明显:

  • 简单查询:从3-5秒降到100-300毫秒
  • 复杂查询:从30-60秒降到3-5秒
  • 并发能力:从5个并发就卡,提升到50个并发没问题
  • 导入性能:从每秒几百条,提升到每秒几万条
  • 资源使用:CPU和内存使用率更合理了

整体性能提升了10倍左右。

十一、经验总结

1. 表设计是基础

StarRocks的性能,70%取决于表设计。

  • 选对数据模型
  • 设对排序键
  • 合理分区和分桶
  • 选对字段类型

表设计好了,性能就不会差。表设计不好,后面怎么优化都没用。

2. 索引是利器

合理使用索引,能大幅提升查询性能。

  • 前缀索引:默认就有,用好排序键
  • Bitmap索引:低基数列
  • Bloom Filter:高基数列的等值查询

3. SQL要写好

SQL写得好不好,对性能影响很大。

  • 用EXPLAIN分析执行计划
  • 避免SELECT *
  • 过滤条件下推
  • 优化Join和聚合
  • 避免在WHERE里用函数

4. 物化视图要巧用

物化视图是StarRocks的一大利器,常用的聚合查询,建物化视图,性能提升明显。

  • 不要建太多
  • 定期检查是否被使用
  • 注意对导入性能的影响

5. 资源要配够

StarRocks对资源要求比较高。

  • CPU、内存、磁盘、网络,都要够
  • 内存尤其重要,不够会 spill 到磁盘
  • 合理设置并发,不是越高越好

6. 监控要跟上

  • 建立完善的监控
  • 定期分析慢查询
  • 定期更新统计信息
  • 持续优化,性能才能持续提升

十二、写在最后

StarRocks是一个很棒的分析型数据库,性能很强,但要用好它,需要花时间学习和优化。

我们从最开始的查询很慢,到后来的亚秒级响应,花了一个月时间。优化的过程,也是学习的过程。表设计、索引、SQL、物化视图、资源配置、监控,每一个环节都很重要。

2022年了,StarRocks发展很快,社区活跃,功能越来越完善。如果你在做数据分析,可以试试StarRocks,它可能会给你带来惊喜。

最后,用一句话总结:"StarRocks性能优化,表设计是基础,索引是利器,SQL要写好,物化视图要巧用,资源要配够,监控要跟上。做好这几点,性能自然就上去了。"

愿你的StarRocks查询,又快又稳。