SelectDB执行分布式Join时,优化器根据统计信息自动选择数据分发方式(Shuffle或Broadcast)。当统计信息不准确或数据经过滤后大小发生显著变化时,优化器的选择可能不是最优的。本文介绍如何通过方括号Hint手动指定Join的分发策略。
Join数据分发方式
分布式Join需要将不同BE节点上的数据汇聚到一起。SelectDB支持以下分发方式:
|
分发方式 |
原理 |
适用场景 |
EXPLAIN输出 |
|
Shuffle |
将Join两侧的数据按Join Key重新Hash分发到各节点 |
两张大表Join |
|
|
Broadcast |
将右表完整广播到所有持有左表数据的节点 |
大表Join小表 |
|
|
Colocate |
数据已共置在相同节点,无需网络传输 |
同一Colocate Group内的表 |
|
优化器默认根据统计信息自动选择:当右表数据量小于广播阈值时选择Broadcast,否则选择Shuffle。如果两张表属于同一Colocate Group,优先使用Colocate Join。
何时需要手动指定
以下情况优化器的自动选择可能不是最优的:
-
统计信息过期:表数据量发生显著变化但统计信息未更新,导致优化器误判表大小。
-
过滤后数据量变化大:右表原始数据很大但WHERE过滤后只剩几百行。优化器按原始行数选择Shuffle,实际上Broadcast更高效。
-
Broadcast导致OOM:右表被选为Broadcast但实际数据量超出预期,广播时内存溢出,需强制使用Shuffle。
Hint语法
在JOIN关键字后使用方括号[]指定分发方式,支持[shuffle]和[broadcast]两种:
指定Shuffle Join
-- 强制使用Shuffle Join
SELECT *
FROM orders o JOIN [shuffle] users u ON o.user_id = u.user_id
WHERE o.order_date >= '2024-01-01';
指定Broadcast Join
-- 强制将右表广播到所有节点
SELECT *
FROM orders o JOIN [broadcast] dim_city c ON o.city_id = c.city_id
WHERE o.order_date >= '2024-01-01';
Hint优先级高于优化器的自动选择,但低于Colocate的自动匹配。如果两张表属于同一Colocate Group且Join Key为分桶键,即使指定了[shuffle]或[broadcast],仍会使用Colocate Join。
实践示例
过滤后小表强制Broadcast
products表原始数据量大,但查询中过滤条件选择性很高,过滤后仅剩少量行。优化器按原始行数选择了Shuffle,但实际Broadcast更高效:
-- 过滤后products表只有少量数据,用Broadcast更高效
SELECT o.*, p.product_name
FROM orders o
JOIN [broadcast] products p ON o.product_id = p.product_id
WHERE p.category = 'limited_edition' AND p.status = 'active';
避免Broadcast导致OOM
统计信息显示右表较小,优化器选择Broadcast,但实际数据量远超统计值,广播时OOM。强制使用Shuffle:
-- 统计信息不准导致Broadcast OOM,强制Shuffle
SELECT o.order_id, u.username
FROM orders o
JOIN [shuffle] users u ON o.user_id = u.user_id;
多表Join分别指定
多表Join场景下,可对每个Join分别指定不同的分发方式:
-- 对不同的Join分别指定分发方式
SELECT o.order_id, u.username, p.product_name
FROM orders o
JOIN [shuffle] users u ON o.user_id = u.user_id
JOIN [broadcast] products p ON o.product_id = p.product_id;
验证Hint生效
通过EXPLAIN查看join op字段确认Hint是否生效:
EXPLAIN SELECT o.*, u.username
FROM orders o JOIN [broadcast] users u ON o.user_id = u.user_id;
-- 在输出中查找:
-- join op: INNER JOIN(BROADCAST)[] 表示Broadcast生效
-- join op: INNER JOIN(PARTITIONED)[] 表示Shuffle生效
-- 输出末尾的 Hint log 会显示:
-- Used: [broadcast]_1 表示Hint已被采用
如果输出末尾的Hint log中该Hint出现在UnUsed或SyntaxError行,说明Hint未生效或语法错误。
使用建议
-
优先通过
ANALYZE TABLE更新统计信息,让优化器自动做出正确判断。 -
Hint属于硬编码,数据分布变化后可能不再适用,应定期评估是否仍需保留。
-
使用前先通过EXPLAIN对比默认计划和Hint计划,确认Hint确实带来了性能提升。
-
建议在测试环境验证Hint效果后再应用到生产SQL。