《MPP/OLAP 数据库实战优化案例:从 1 小时到 2 分钟,SQL 调优 + 存储优化 + 数据倾斜解决》

发布时间:2026/7/1 1:03:32
《MPP/OLAP 数据库实战优化案例:从 1 小时到 2 分钟,SQL 调优 + 存储优化 + 数据倾斜解决》 背景说明本文记录了笔者在Greenplum数据仓库日常运维中遇到的 6 个真实性能问题涵盖 SQL 调优、执行计划修复、数据倾斜处理、存储优化等场景。这些优化思路同样适用于Doris、StarRocks、ClickHouse等 MPP 架构的 OLAP 数据库因为它们的核心原理相通分布式计算 列式存储 分区剪枝 本地 Join。一、SQL 极致优化拆表 UNION30 倍提升问题现象某租户核心脚本运行超时1 小时影响下游报表产出。根因分析排查 SQL 发现同一张表自关联时关联条件中的字段相同导致优化器生成了笛卡尔积执行计划数据量爆炸式增长。优化动作将大表按字段切分为三部分分别构造临时表各自关联后通过UNION ALL合并结果。sql-- 优化前简化示例实际 SQL 更复杂 SELECT * FROM large_table a JOIN large_table b ON a.id b.id -- 相同字段自关联产生笛卡尔积 WHERE ... -- 优化后拆表 UNION CREATE TEMP TABLE tmp1 AS SELECT ... FROM large_table WHERE condition1; CREATE TEMP TABLE tmp2 AS SELECT ... FROM large_table WHERE condition2; CREATE TEMP TABLE tmp3 AS SELECT ... FROM large_table WHERE condition3; SELECT * FROM tmp1 JOIN ... UNION ALL SELECT * FROM tmp2 JOIN ... UNION ALL SELECT * FROM tmp3 JOIN ...;优化结果耗时1 小时 →2 分钟性能提升30 倍Doris / StarRocks 适用性✅完全适用。Doris 同样支持UNION ALL和临时表CTE 或CREATE TEMP VIEW拆分大表后可以显著减少单次 Join 的数据量。如果 Join 涉及 Bucket 分布还可以利用Colocation Join进一步优化。二、循环逻辑重构三次 Join → 一次 Cross Join问题现象某脚本使用循环对同一张表做了三次JOIN执行效率低下。根因分析循环中逐次执行JOIN导致同一张表被扫描三次网络和 IO 开销成倍增加。优化动作将三次JOIN合并为一次CROSS JOIN 条件聚合三次扫描变一次。sql-- 优化前伪代码 FOR each condition: INSERT INTO result SELECT ... FROM table JOIN table ON ... -- 优化后一次 CROSS JOIN CASE WHEN SELECT CASE WHEN condition1 THEN ... END AS col1, CASE WHEN condition2 THEN ... END AS col2, CASE WHEN condition3 THEN ... END AS col3 FROM table CROSS JOIN table GROUP BY ...;优化结果耗时减半性能提升100%Doris / StarRocks 适用性✅完全适用。Doris 中同样应避免在循环中反复扫描同一张表优先使用CASE WHEN 聚合或UNION ALL替代多次扫描。Doris 的向量化执行引擎对CASE WHEN和聚合操作的优化非常好。三、执行计划修复统计信息过旧导致优化器选错路径问题现象某任务运行突然变慢SQL 和索引均无问题执行计划看起来“不合理”。根因分析查看执行计划发现优化器选择了错误的 Join 顺序或错误的表扫描方式。进一步排查发现表统计信息pg_statistic已过时导致优化器无法准确估算数据量。优化动作执行ANALYZE更新统计信息让优化器重新选择执行路径。sql-- Greenplum / PostgreSQL ANALYZE table_name; -- Doris ANALYZE TABLE table_name; -- ClickHouse OPTIMIZE TABLE table_name;优化结果执行计划恢复正常查询性能回归正常水平。Doris / StarRocks 适用性✅高度适用。Doris 同样依赖统计信息ANALYZE TABLE进行 CBO基于代价的优化统计信息过旧同样会导致执行计划退化。建议定期执行ANALYZE TABLE或配置自动收集策略。四、避免重分布Shuffle开销分区键对齐实现本地 Join问题现象两张大表JOIN时重分布Shuffle带来巨大的网络和 IO 开销甚至跑不出数据。根因分析两表的分区键不一致导致 Join 时数据需要在不同节点间重新分布产生大量网络传输。优化动作将两张表的分区键设置为一致包括分区键的顺序、字段类型完全对齐。这样 Join 时数据已经在同一节点上实现本地 JoinLocal Join避免 Shuffle。sql-- 优化前分区键不一致 -- 表 A 按 date 分区表 B 按 category 分区 -- 优化后统一按 date 分区 -- 表 APARTITION BY date -- 表 BPARTITION BY date与 A 完全一致优化结果无需重分区减少网络和 IO 开销几个小时跑不完的任务缩短到几分钟Doris / StarRocks 适用性✅核心适用场景。Doris 的Colocation Join就是专门解决这个问题的将两表按相同的 Bucket 分布实现本地 Join完全避免 Shuffle。Greenplum 中叫“分区键对齐”Doris 中叫Colocation Group原理完全一致。sql-- Doris Colocation Join 示例 CREATE TABLE table_a ( ... ) DISTRIBUTED BY HASH(order_id) BUCKETS 16 PROPERTIES (colocate_with group1); CREATE TABLE table_b ( ... ) DISTRIBUTED BY HASH(order_id) BUCKETS 16 PROPERTIES (colocate_with group1);五、数据倾斜处理大经销商占 30% 数据导致任务卡慢问题现象核心任务运行耗时40 分钟某个大经销商的数据占全表的30%导致数据严重倾斜部分节点过载。根因分析表没有按字段分区所有数据随机分布导致大经销商的数据集中在少数节点上造成计算倾斜。优化动作备份原表按经销商标识字段重新分区如按dealer_id的哈希值或范围分区同步分区到新表重新加载数据sql-- 优化前无分区 CREATE TABLE sales (dealer_id INT, amount DECIMAL); -- 优化后按 dealer_id 分区 CREATE TABLE sales (dealer_id INT, amount DECIMAL) PARTITION BY RANGE (dealer_id) ( PARTITION p1 VALUES LESS THAN (100), PARTITION p2 VALUES LESS THAN (200), ... );优化结果数据均匀分布到各节点耗时从 40 分钟降至 15 分钟Doris / StarRocks 适用性✅完全适用。Doris 中数据倾斜同样常见解决方案包括调整 Bucket 键选择倾斜列作为分桶键或加盐加随机数打散使用 Dynamic Partition按时间或业务字段动态分区开启 Load 时的数据均衡enable_auto_bucket true六、存储优化分区 压缩查询性能提升 50%问题现象大表查询越来越慢全表扫描成本高存储空间紧张。根因分析表未做分区每次查询都是全表扫描未启用压缩存储成本高IO 读取量大优化动作按主键分区存储提升点查性能历史表按时间分区如按月分区查询时可分区裁剪启用压缩如 ZSTD / LZ4减少存储和 IOsql-- Greenplum按日期分区 压缩 CREATE TABLE sales ( sale_date DATE, amount DECIMAL ) PARTITION BY RANGE (sale_date) ( PARTITION p2024_01 START (2024-01-01) END (2024-02-01), PARTITION p2024_02 START (2024-02-01) END (2024-03-01) ) WITH (appendonlytrue, compresstypezstd);优化结果查询性能提升 50%存储成本显著降低Doris / StarRocks 适用性✅完全适用且支持更好。分区Doris 支持PARTITION BY RANGE / LIST自动分区裁剪压缩Doris 默认使用ZSTD / LZ4压缩可配置compression参数冷热分层Doris 还支持 SSD HDD 自动分层进一步降低成本sql-- Doris 分区 压缩示例 CREATE TABLE sales ( sale_date DATE, amount DECIMAL ) PARTITION BY RANGE (sale_date) ( PARTITION p2024_01 VALUES LESS THAN (2024-02-01), PARTITION p2024_02 VALUES LESS THAN (2024-03-01) ) PROPERTIES ( compression ZSTD );总结优化思路通用性对照表优化场景Greenplum 中的做法Doris / StarRocks 对应做法是否通用SQL 拆表 UNIONCTE / 临时表 UNION ALLCTE UNION ALL✅ 通用循环改一次扫描CASE WHEN 聚合CASE WHEN 聚合 / 多表 UNION✅ 通用统计信息过旧ANALYZEANALYZE TABLE✅ 通用本地 Join防 Shuffle分区键对齐Colocation Join机制相同✅ 通用数据倾斜按倾斜字段重新分区加盐 / 调整 Bucket 键✅ 通用分区 压缩Range 分区 ZSTDRange 分区 ZSTD / LZ4✅ 通用结尾总结MPP/OLAP 数据库虽然引擎各异Greenplum、Doris、StarRocks、ClickHouse但性能优化的底层逻辑是相通的减少数据扫描量分区、索引、列裁剪减少数据移动本地 Join、分区键对齐让优化器做出正确决策更新统计信息均匀分布数据避免倾斜降低 IO 成本压缩、冷热分层掌握这些通用优化思路无论换什么 OLAP 引擎都能快速上手调优。