StarRocks 之所以快,除了向量化执行引擎外,还依赖丰富的数据组织和索引技术。
核心技术
1. 物化视图 (Materialized View)
- 文件 :
01_materialized_view.sql - 原理: 空间换时间。预先计算好聚合结果(如 SUM, COUNT),查询时自动路由。
- 类型:
- 单表同步 MV (示例中演示): 实时更新,强一致。
- 多表异步 MV (2.4+): 支持复杂 Join,定期刷新。
2. 索引 (Indexing)
- 文件 :
02_indexes.sql - Bitmap Index : 适合性别、省份等枚举值少的列。加速
WHERE col = 'A'。 - Bloom Filter : 适合 ID、UUID 等取值多的列。加速
WHERE id = 123,快速跳过不包含该 ID 的数据块。 - Prefix Index (前缀索引): 默认建立在排序键 (Sort Key) 的前 36 字节。建表时合理设置 Key 顺序至关重要!
3. 分区与分桶 (Partition & Bucket)
- 文件 :
03_partitioning.sql - Partition: 宏观切割,通常按时间。查询带时间范围时直接裁剪掉无关分区。
- Bucket: 微观切割,按 Hash。利用集群并行计算能力。
最佳实践
- 排序键 (Sort Key): 将查询频率最高的过滤列放在 Key 的最前面(利用前缀索引)。
- 分区 : 大表(亿级以上)务必按时间分区,并开启动态分区 (
dynamic_partition)。
sql
-- Phase 4: 查询加速
-- 01_materialized_view.sql
-- 同步物化视图 (Synchronous Materialized View)
USE learn_starrocks;
-- 假设我们有一个销售明细表
CREATE TABLE IF NOT EXISTS sales_records (
record_id INT,
seller_id INT,
store_id INT,
sale_date DATE,
sale_amt DECIMAL(10, 2)
)
ENGINE=OLAP
DUPLICATE KEY(record_id)
DISTRIBUTED BY HASH(record_id) BUCKETS 3
PROPERTIES ("replication_num" = "1");
-- 场景:我们经常需要查询每个店铺的销售总额
-- SELECT store_id, SUM(sale_amt) FROM sales_records GROUP BY store_id;
-- 这种查询在数据量大时,每次都要扫描全表并聚合,很慢。
-- 创建物化视图:预先计算好聚合结果
-- 注意:StarRocks 会自动维护 MV 的数据一致性(源表插入数据,MV 自动更新)
CREATE MATERIALIZED VIEW mv_store_sales
AS
SELECT
store_id,
SUM(sale_amt) AS total_amt
FROM sales_records
GROUP BY store_id;
-- 验证 MV 是否生效
-- 插入数据
INSERT INTO sales_records VALUES
(1, 101, 1, '2023-01-01', 100.00),
(2, 102, 1, '2023-01-01', 200.00),
(3, 103, 2, '2023-01-01', 50.00);
-- 执行查询
-- StarRocks 优化器会自动路由到 mv_store_sales 视图,而不需要显式查询视图
EXPLAIN SELECT store_id, SUM(sale_amt) FROM sales_records GROUP BY store_id;
-- 在 EXPLAIN 结果中,如果看到 `Rollup: mv_store_sales`,说明命中 MV
sql
-- Phase 4: 查询加速
-- 02_indexes.sql
-- 索引技术:Bitmap Index 和 Bloom Filter Index
USE learn_starrocks;
CREATE TABLE IF NOT EXISTS user_events (
event_id BIGINT,
user_id INT,
event_type VARCHAR(20), -- 基数小 (Login, Logout, Click) -> 适合 Bitmap
device_uuid VARCHAR(100), -- 基数大 -> 适合 Bloom Filter
event_time DATETIME
)
ENGINE=OLAP
DUPLICATE KEY(event_id)
DISTRIBUTED BY HASH(event_id) BUCKETS 3
PROPERTIES (
"replication_num" = "1",
-- 1. Bloom Filter 索引
-- 适用于高基数列的等值查询 (user_id = 123)
-- 注意:Bloom Filter 只能判断"可能存在"或"一定不存在",用于快速过滤文件块
"bloom_filter_columns" = "device_uuid"
);
-- 2. Bitmap 索引
-- 适用于低基数列 (枚举值少) 的查询,支持等值、IN、OR
-- 可以在建表后添加,也可以建表时指定
CREATE INDEX idx_event_type ON user_events(event_type) USING BITMAP COMMENT "Bitmap index for event type";
-- 验证
SHOW INDEX FROM user_events;
sql
-- Phase 4: 查询加速
-- 03_partitioning.sql
-- 分区与分桶 (Partitioning & Bucketing)
USE learn_starrocks;
-- 分区 (Partition): 通常按时间划分 (按天/按月)。
-- 分桶 (Bucket): 在分区内进一步打散数据,通常按 ID 哈希。
-- 目的:查询时通过分区裁剪 (Partition Pruning) 减少扫描的数据量。
CREATE TABLE IF NOT EXISTS bill_detail (
bill_id BIGINT,
bill_date DATE,
amount DECIMAL(10, 2)
)
ENGINE=OLAP
DUPLICATE KEY(bill_id, bill_date)
PARTITION BY RANGE(bill_date) (
-- 手动创建分区
PARTITION p202301 VALUES LESS THAN ("2023-02-01"),
PARTITION p202302 VALUES LESS THAN ("2023-03-01"),
PARTITION p202303 VALUES LESS THAN ("2023-04-01")
)
DISTRIBUTED BY HASH(bill_id) BUCKETS 3
PROPERTIES (
"replication_num" = "1",
-- 动态分区配置 (强烈推荐):自动管理分区创建和删除
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "MONTH",
"dynamic_partition.start" = "-2", -- 保留过去2个月
"dynamic_partition.end" = "2", -- 预创建未来2个月
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "3"
);
-- 查询优化演示
-- 查询 2023-01 的数据时,只会扫描 p202301 分区,忽略其他分区
SELECT * FROM bill_detail WHERE bill_date >= '2023-01-01' AND bill_date < '2023-01-15';
-- 查看分区情况
SHOW PARTITIONS FROM bill_detail;