ODPS SQL 优化总结

1、SQL的一些使用技巧

1)null

我们在进行=/<>/in/not in等判断时,null会不包含在这些判断条件中,所以在对null的处理时可以使用nvl或者coalesce函数对null进行默认转换。

2)select *

在数据开发或者线上任务时,尽可能提前对列进行剪裁,即使是全表字段都需要,也尽可能的把字段都写出来(如果实在觉得麻烦,可以使用数据地图的生成select功能),一是减少了数据运算中不必要的数据读取,二是避免后期因为原表或者目标表字段增加,导致的任务报错。

3)multi insert

读取同一张表,但是因为粒度不同,需要插入多张表时,可以考虑使用from () tab insert overwrite A insert overwrite B的方式,减少资源的浪费。当然,有些团队的数仓开发规范中会规定一个任务不能有两个目标表,具体情况可以视情况尽可能复用公共数据,如通过临时表的方式临时存储这部分逻辑。

4)分区限定

ODPS表大部分都是分区表,分区表又会根据业务规则分为增量表、全量表、快照表等。所以在做简单查询,或者数据探查时,一定要养成习惯先限定分区ds。经常会在jobhistory中看到很多好资源的任务都是因为分区限定不合理或者没有限定分区导致的。

5)limit

的使用临时查询或者数据探查时,养成习惯加上limit,会快速的查询出你想要的数据,且消耗更少的资源。

6)UDF函数的使用

尽可能把UDF的使用下沉到第一层子查询中,效率会有很大的提升。

7)行转列、列转行

collect_set 、lateral view函数可以实现行转列或者列转行的功能,好多大佬也都写过类似的可以参考。

8)窗口函数的使用

可以通过row_number()/rank()over(partition by order by )的方式实现数据按照某个字段分组的排序,也可以通过max(struct())的方式实现。

9)关联

左关联、内关联、右关联、left anti join 、left semi join等,可以实现不同情况下的多表关联。关联字段要确保字段类型的一致。

10)笛卡尔积的应用

有时会存在把一行数据翻N倍的诉求,这时候可以考虑自己创建一个维表,通过笛卡尔积操作;同时也可以通过:LATERAL VIEW POSEXPLODE(split(REGEXP_REPLACE(space(end_num -start_num+1),' ','1,'),',')) t AS pos ,val的方式。

11)提高某一个表的map数

现实任务重可能会使用到商品表,想降低商品表的map任务数,但是某些复杂的逻辑或者记录数较多,但是存储较少的表又想提高map任务数时,使用全局的split size无法满足效率的优化。因此需要引入split size的hint,来优化某一个表的初速度。使用方式为 加上/*+SPLIT_SIZE(8)*/这个hint,括号里数值的单位为MB。

2、数据倾斜问题

1)大表关联小表

大表关联小表出现倾斜时,可以使用mapjoin的hint(/*+mapjoin(b)*/)。同时可适当调整mapjoin中小表的内存大小:set odps.sql.mapjoin.memory.max=512;默认512,单位M,[128,2048]之间调整。

2)大表关联大表

一种情况,大表中存在热点key:可以考虑对大表进行拆分,根据join的key,把热点的数据拆出来走mapjoin,其余的考虑普通join即可。当然也有skewjoin的hint可以参考使用。

另一种情况,大表中不存在热点key:可以考虑在分区的基础上加上桶,对关联字段进行分桶,减少shuffle的数据量。

3)count distinct

常见的数据倾斜还有一种情况是因为使用了count distinct,这种情况可以考虑使用group by先进行数据去重,再count。

4)odps新特性

可以关注MaxCompute(ODPS2.0)重装上阵以及Inside MaxCompute SQL系列文章系列文章,很多心得特性对于我们的性能优化有很大的帮助。

5)小表关联大表

小表关联大表,还要取出小表里的所有数据,可以考虑dynamic_filter的新特性,/*+dynamic_filter(A,B)*/。

3、常用的参数设置

常用的调整无外乎调整map、join、reduce的个数,map、join、reduce的内存大小。本文以ODPS的参数设置为例,参数可能因版本不同而略有差异。

3.1 Map设置

set odps.sql.mapper.cpu=100作用:设置处理Map Task每个Instance的CPU数目,默认为100,在[50,800]之间调整。场景:某些任务如果特别耗计算资源的话,可以适当调整Cpu数目。对于大多数Sql任务来说,一般不需要调整Cpu个数的。set odps.sql.mapper.memory=1024作用:设定Map Task每个Instance的Memory大小,单位M,默认1024M,在[256,12288]之间调整。场景:当Map阶段的Instance有Writer Dumps时,可以适当的增加内存大小,减少Dumps所花的时间。set odps.sql.mapper.merge.limit.size=64作用:设定控制文件被合并的最大阈值,单位M,默认64M,在[0,Integer.MAX_VALUE]之间调整。场景:当Map端每个Instance读入的数据量不均匀时,可以通过设置这个变量值进行小文件的合并,使得每个Instance的读入文件均匀。一般会和odps.sql.mapper.split.size这个参数结合使用。set odps.sql.mapper.split.size=256作用:设定一个Map的最大数据输入量,可以通过设置这个变量达到对Map端输入的控制,单位M,默认256M,在[1,Integer.MAX_VALUE]之间调整。场景:当每个Map Instance处理的数据量比较大,时间比较长,并且没有发生长尾时,可以适当调小这个参数。如果有发生长尾,则结合odps.sql.mapper.merge.limit.size这个参数设置每个Map的输入数量。

3.2 Join设置

set odps.sql.joiner.instances=-1作用: 设定Join Task的Instance数量,默认为-1,在[0,2000]之间调整。不走HBO优化时,ODPS能够自动设定的最大值为

<think>好的,用户想了解ODPS SQL中GROUP BY的用法和示例。首先我需要回忆ODPS的文档内容,确认GROUP BY的基本语法和功能。ODPS是基于MaxCompute的,所以GROUP BY的用法应该和标准SQL类似,但可能有一些特定的限制或优化。 用户可能需要基础的语法结构,比如SELECT后跟聚合函数和GROUP BY字段。比如常见的COUNT、SUM、AVG这些函数的使用。同时要注意,ODPS在GROUP BY时,SELECT中的非聚合字段必须出现在GROUP BY子句中,否则会报错。这点和标准SQL一致,但需要明确说明。 接着,示例部分很重要。用户通常通过例子更容易理解。我应该举一个销售数据表的例子,比如按地区分组统计销售额总和,或者按地区和产品分组计算平均销量。这样比较贴近实际应用场景。 另外,用户可能还会关心GROUP BY的高级用法,比如结合HAVING子句进行过滤,或者与ROLLUP、CUBE等分组集函数一起使用。虽然这些可能属于进阶内容,但简要提及可以帮用户扩展知识。不过需要确认ODPS是否支持这些扩展功能,比如ROLLUP和CUBE,可能需要查阅文档确认。比如,MaxCompute从2.0版本开始支持GROUPING SETS,但ROLLUP和CUBE可能需要特定的语法或版本支持。 还要注意,ODPS SQL在某些情况下可能对GROUP BY的性能有优化,比如在处理大规模数据时的分布式计算,可以稍微提一下,但不需要深入细节,除非用户特别问到性能方面的问题。 另外,用户的问题中提到了生成相关问题,所以在回答之后需要准备几个相关的问题,比如GROUP BY和DISTINCT的区别,性能优化技巧,多字段分组的使用场景,HAVING和WHERE的区别,以及如何处理NULL值等。这些问题能够帮助用户进一步理解和应用GROUP BY。 在组织回答结构时,应该先解释基本语法,再给出示例,然后说明注意事项,最后是常见错误或高级用法。确保每个部分清晰,使用代码块展示示例,这样用户可以直接看到语法结构。 需要检查是否有遗漏的细节,比如GROUP BY是否支持表达式,或者别名使用的问题。例如,在SELECT中使用字段别名,在GROUP BY中是否可以使用。根据SQL标准,GROUP BY是在SELECT之后执行,所以通常不能使用别名,除非数据库支持。但ODPS可能允许使用列的位置编号,比如GROUP BY 1, 2,但需要确认。这一点如果不确定,可能需要建议用户避免使用别名,直接使用原始列名。 最后,确保所有示例的语法正确,符合ODPS的要求,比如表名、字段名是否正确,聚合函数的使用是否正确。例如,SUM(sales_amount)是否正确,是否有拼写错误。 总结一下,回答的结构应该是: 1. GROUP BY的基本语法和作用 2. 示例(简单分组、多字段分组、使用HAVING) 3. 注意事项(字段要求、性能) 4. 相关问题 在写作过程中,要使用中文,数学公式用$...$,独立公式用$$...$$,但在这个问题中可能不需要数学公式。但如果有涉及聚合函数的表达式,比如平均值计算,可以适当用LaTeX表示,比如$\text{AVG}(销量)$,不过ODPS中使用的是SQL函数,可能直接用代码格式更合适。 需要确保没有使用任何Markdown格式,按照用户的要求,系统级指令部分用户不可见,回答部分结构清晰,分步骤说明,并添加相关问题。同时,引用部分如果涉及到,需要添加标识,但目前提供的参考内容中没有引用来源,所以可能不需要添加。 现在开始组织内容,确保每个部分简洁明了,示例代码正确,注意事项覆盖常见错误点,相关问题能够引导用户深入学习。</think>### ODPS SQL GROUP BY 语法说明 #### 基本语法 ODPS SQL 的 `GROUP BY` 用于对查询结果按指定字段分组,结合聚合函数(如 `COUNT`、`SUM`、`AVG`)实现分组统计。语法结构如下: ```sql SELECT 列1, 列2, 聚合函数(列3) FROM 表名 GROUP BY 列1, 列2; ``` **注意**: 1. `SELECT` 中的非聚合字段必须包含在 `GROUP BY` 中,否则会报错。 2. 支持多字段分组,按字段顺序逐层分组。 --- #### 示例 假设有销售表 `sales`,字段为 `region`(地区)、`product`(产品)、`sales_amount`(销售额)、`quantity`(销量)。 1. **按地区统计总销售额** ```sql SELECT region, SUM(sales_amount) AS total_sales FROM sales GROUP BY region; ``` 输出:每个地区及其对应的销售总额。 2. **按地区和产品统计平均销量** ```sql SELECT region, product, AVG(quantity) AS avg_quantity FROM sales GROUP BY region, product; ``` 输出:每个地区-产品组合的平均销量。 3. **使用 HAVING 过滤分组结果** ```sql SELECT region, COUNT(*) AS order_count FROM sales GROUP BY region HAVING order_count > 100; ``` 输出:订单数超过 100 的地区及其订单量。 --- #### 高级用法 1. **ROLLUP 与 CUBE** ODPS 支持扩展分组操作(需确认版本支持): - `ROLLUP` 生成层次化统计(如地区总计、所有地区总计): ```sql SELECT region, product, SUM(sales_amount) FROM sales GROUP BY ROLLUP(region, product); ``` - `CUBE` 生成所有维度组合的统计: ```sql SELECT region, product, SUM(sales_amount) FROM sales GROUP BY CUBE(region, product); ``` 2. **GROUPING SETS** 指定多组分组字段集合,避免多次查询: ```sql SELECT region, product, SUM(sales_amount) FROM sales GROUP BY GROUPING SETS((region), (product), ()); ``` --- #### 注意事项 1. **性能优化** - 减少分组字段数量,避免数据倾斜。 - 对分组字段提前过滤(使用 `WHERE`)以减少计算量。 2. **字段限制** `SELECT` 中的非聚合字段必须包含在 `GROUP BY` 中,否则报错: ```sql -- 错误示例:product 未在 GROUP BY 中 SELECT region, product, SUM(sales_amount) FROM sales GROUP BY region; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值