HSQL 调优
下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/org-e3rjs5bu--hsql-tuning.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @org-e3rjs5bu/hsql-tuning。在编写、审查、解释或调优 Hive SQL / HQL / SparkSQL (HSQL) 时使用。当遇到以下情况时触发(Trigger):DISTINCT vs GROUP BY、数据倾斜、ORDER BY vs SORT BY、DISTRIBUTE BY、CLUSTER BY、分区裁剪、分桶、ORC、COUNT(DISTINCT)、mapjoin、小文件、全表扫描、EXPLAIN,或者 Hive/Spark 的 join(连接)与 group-by(分组)性能问题。
阅读全文 (展开查看完整说明)
概述
HSQL 指 Hive SQL(HQL),常见执行引擎是 MapReduce 或 SparkSQL。性能首先由扫了多少数据、shuffle 是否倾斜决定,不是由单机 SQL 习惯决定。
Hive 的 DISTRIBUTE BY 是查询时指定 reducer 分区,不是 GaussDB 建表的 DISTRIBUTE BY HASH。MPP 分布列调优用 gaussdb-sql-tuning。
何时使用
- 写/改 Hive / SparkSQL 的建表、JOIN、GROUP BY、去重、排序、抽样
- 作业跑十几分钟以上、个别 task 特别慢、spill / OOM、小文件爆炸
- 需要解释 分区 vs 分桶、ORDER BY vs SORT BY、ORC、分区裁剪
不要用本技能处理:单机 MySQL/Oracle、GaussDB(DWS) 分布列、集群安装运维。
调优收益顺序
数据倾斜 > 全表扫描 > 普通 SQL 改写 > 参数调整
先消灭倾斜和无效扫描。只改 hive.exec.reducers 救不了热点 key。
写任何表之前
分析表默认用 ORC,并按查询谓词分区。JOIN/聚合键再分桶。
CREATE TABLE dwd_order_detail (
order_id STRING,
cust_id STRING,
amount DECIMAL(18,2),
order_ts TIMESTAMP
)
PARTITIONED BY (dt STRING)
CLUSTERED BY (cust_id) INTO 32 BUCKETS
STORED AS ORC
TBLPROPERTIES (
'orc.compress'='SNAPPY',
'orc.bloom.filter.columns'='cust_id'
);| 场景 | 选择 |
|---|---|
| 查询几乎都带日期/月份 | PARTITIONED BY (dt) |
| 两表按同一高基数列 JOIN | 两表都 CLUSTERED BY (该列),桶数相同 |
| 维表很小 | 大表 JOIN 时走 mapjoin / broadcast |
| 分区列枚举爆炸 | 禁止;会出小文件 |
| 文本表做分析查询 | 改成 ORC 再查 |
分区、分桶、ORC:references/storage.md
四种排序,不要混
| 写法 | 实际行为 | 何时用 |
|---|---|---|
ORDER BY col | 全局排序,一个 reduce | 只要全局 Top N,且已过滤到很小 |
SORT BY col | 每个 reducer 内排序 | 不要求全局有序 |
DISTRIBUTE BY col | 同 key 进同一 reducer | 为后续同 key 处理做准备 |
CLUSTER BY col | DISTRIBUTE BY + SORT BY | 同 key 聚集且 reducer 内有序 |
CLUSTER BY id LIMIT 1000 不等于 全局 ORDER BY id LIMIT 1000。每组取 1000 行用窗口函数。
完整正反例:references/sql-patterns.md
SQL 改写速查
| 不要 | 改成 |
|---|---|
SELECT DISTINCT ... | GROUP BY 业务键 |
COUNT(DISTINCT x) | 先 GROUP BY x,再 COUNT(*) |
| 一层 SQL 算几十个特征 | 拆多段,中间结果落物理表 |
| 同一表达式写 3 遍 | 先算出一列,再引用 |
| 只用 CTE / 视图串很长 | 中间结果 CREATE TABLE ... STORED AS ORC |
ORDER BY 全表再 LIMIT | 先过滤/分区裁剪;组内 Top N 用 ROW_NUMBER() |
NOT IN (SELECT ...) | NOT EXISTS 或 LEFT JOIN ... WHERE b.id IS NULL |
WHERE func(分区列)= | 对分区列写范围/等值,让裁剪生效 |
'%keyword%' | 能右模糊就 'keyword%' |
| 大表直接 JOIN 后再过滤 | 单表先过滤再 JOIN |
倾斜先于一切
- 小表 JOIN 大表:mapjoin / broadcast,把小表做进内存。
- 大表 JOIN 大表:热点 key 加盐打散,或倾斜键单独算完再
UNION ALL。 GROUP BY/COUNT(DISTINCT)倾斜:先 map 端聚合;仍偏就两阶段聚合或随机分区。
SET hive.map.aggr=true;
SET hive.groupby.skewindata=true;
SET hive.auto.convert.join=true;参数只是辅助。根因仍是 key 分布。处理步骤:references/skew.md
诊断
先看扫了哪些分区、shuffle 是否一个 task 独大,最后才调参数。
EXPLAIN:分区有没有被裁掉,JOIN 是 Map Join 还是 Shuffle Join- 输入路径是否只命中目标
dt=分区 - Spark UI / MR 计数:个别 task 行数或时长是否远超均值
- 输出目录是否大量小文件
- 仍慢:改 SQL / 表结构,而不是先加 executor
诊断步骤:references/diagnose.md
交付检查
写完 SQL 后按顺序回答,缺一项就改:
- 分析表是否 ORC,查询能否命中分区?
- JOIN / GROUP BY 键是否与分桶键一致,或小表已 mapjoin?
- 有没有
DISTINCT、COUNT(DISTINCT)、ORDER BY全表、SELECT *? - 同一表达式有没有重复算?中间结果有没有落表?
- 热点 key 有没有倾斜预案(加盐 / 拆键 / 两阶段聚合)?
- 分区列有没有包函数?会不会写出大量小文件?
常见借口
| 借口 | 事实 |
|---|---|
| 这就是普通 SQL | 语法像 SQL,执行是 MR/Spark。ORDER BY 会收成一个 reduce。 |
| 先跑通再分区 | 没分区就是全表扫描;事后改分区要重导数据。 |
| DISTINCT 更短 | 短查询不等于便宜。去重是全量 shuffle。 |
| 调大并行度就行 | 热点 key 永远进同一个 task。并行度救不了倾斜。 |
| CTE 已经够清晰 | 过长 CTE 重复计算且难落盘;复杂中间结果要物理表。 |
| Hive 的 DISTRIBUTE BY 就是分布列 | 那是查询时分区。建表均匀分布靠 CLUSTERED BY。 |