使用Hint调整Join Shuffle方式

更新时间:
复制 MD 格式

SelectDB执行分布式Join时,优化器根据统计信息自动选择数据分发方式(ShuffleBroadcast)。当统计信息不准确或数据经过滤后大小发生显著变化时,优化器的选择可能不是最优的。本文介绍如何通过方括号Hint手动指定Join的分发策略。

Join数据分发方式

分布式Join需要将不同BE节点上的数据汇聚到一起。SelectDB支持以下分发方式:

分发方式

原理

适用场景

EXPLAIN输出

Shuffle

Join两侧的数据按Join Key重新Hash分发到各节点

两张大表Join

INNER JOIN(PARTITIONED)

Broadcast

将右表完整广播到所有持有左表数据的节点

大表Join小表

INNER JOIN(BROADCAST)

Colocate

数据已共置在相同节点,无需网络传输

同一Colocate Group内的表

INNER JOIN(COLOCATE[])

优化器默认根据统计信息自动选择:当右表数据量小于广播阈值时选择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 GroupJoin 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出现在UnUsedSyntaxError行,说明Hint未生效或语法错误。

使用建议

  • 优先通过ANALYZE TABLE更新统计信息,让优化器自动做出正确判断。

  • Hint属于硬编码,数据分布变化后可能不再适用,应定期评估是否仍需保留。

  • 使用前先通过EXPLAIN对比默认计划和Hint计划,确认Hint确实带来了性能提升。

  • 建议在测试环境验证Hint效果后再应用到生产SQL。