-
Notifications
You must be signed in to change notification settings - Fork 5
/
MaxComputer.txt
4060 lines (3310 loc) · 179 KB
/
MaxComputer.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
https://help.aliyun.com/document_detail/73771.html?spm=a2c4g.11186623.2.14.52e84c309cTwZK
AccessKey
AccessKey(简称AK,包括Access Key Id和Access Key Secret),是访问阿里云API的密钥,在阿里云官网注册云账号后,可在accesskeys管理页面生成,用于标识用户,为访问MaxCompute或者其他云产品做签名验证。Access Key Secret必须保密。
安全
MaxCompute多租户数据安全体系,主要包括用户认证、项目空间的用户与授权管理、跨项目空间的资源分享以及项目空间的数据保护。关于MaxCompute安全操作的更多详情请参见安全指南。
C
Console
MaxCompute Console是运行在Window/Linux下的客户端工具,通过Console可以提交命令完成Project管理、DDL、DML等操作。对应的工具安装和常用参数请参见客户端。
D
Data type
MaxCompute表中所有列对应的数据类型。目前支持的数据类型详情请参见基本概念>数据类型。
DDL
Data Definition Language(数据定义语言)。比如创建表、创建视图等操作,MaxCompute DDL语法请参见用户指南>DDL语句。
DML
Data Manipulation Language(数据操作语言)。比如INSERT操作,MaxCompute DML语法请参见用户指南>INSERT操作。
F
fuxi
伏羲(fuxi)是飞天平台内核中负责资源管理和任务调度的模块,同时也为应用开发提供了一套编程基础框架。MaxCompute底层任务调度模块即fuxi的调度模块。
I
Instance(实例)
作业的一个具体实例,表示实际运行的Job,类同Hadoop中Job的概念。详情请参见基本概念>任务实例。
M
MapReduce
MaxCompute处理数据的一种编程模型,通常用于大规模数据集的并行运算。您可以使用MapReduce提供的接口(Java API)编写MapReduce程序,来处理MaxCompute中的数据。编程思想是将数据的处理方式分为Map(映射)和Reduce(规约)。
在正式执行Map前,需要将输入的数据进行分片。所谓分片,就是将输入数据切分为大小相等的数据块,每一块作为单个Map Worker的输入被处理,以便于多个Map Worker同时工作。每个Map Worker在读入各自的数据后,进行计算处理,最终通过Reduce函数整合中间结果,从而得到最终计算结果。详情请参见MapReduce。
O
ODPS
ODPS是MaxCompute的原名。
P
Partition(分区)
分区Partition是指一张表下,根据分区字段(一个或多个组合)对数据存储进行划分。也就是说,如果表没有分区,数据是直接放在表所在的目录下。如果表有分区,每个分区对应表下的一个目录,数据是分别存储在不同的分区目录下。关于分区的更多介绍请参见基本概念>分区。
Project(项目)
项目空间(Project)是MaxCompute的基本组织单元,它类似于传统数据库的Database或Scheme的概念,是进行多用户隔离和访问控制的主要边界。详情请参见基本概念>项目空间。
R
Role(角色)
角色是MaxCompute安全功能里使用的概念,可以看成是拥有相同权限的用户的集合。多个用户可以同时存在于一个角色下,一个用户也可以隶属于多个角色。给角色授权后,该角色下的所有用户拥有相同的权限。关于角色管理的更多介绍请参见安全指南>角色管理。
Resource(资源)
资源(Resource)是MaxCompute中特有的概念。您如果想使用MaxCompute的自定义函数(UDF)或MapReduce功能,都需要依赖资源来完成。详情请参见基本概念>资源。
S
SDK
Software Development Kits软件开发工具包。一般都是一些被软件工程师用于为特定的软件包、软件实例、软件框架、硬件平台、操作系统、文档包等建立应用软件的开发工具的集合。MaxCompute目前支持Java SDK和Python SDK。
授权
项目空间管理员或者project owner授予您对MaxCompute中的Object(或称之为客体,例如表,任务,资源等)进行某种操作的权限,包括读、写、查看等。授权的具体操作请参见安全指南>用户管理。
沙箱
MaxCompute MapReduce及UDF程序在分布式环境中运行时受到Java沙箱的限制。
T
Table(表)
表是MaxCompute的数据存储单元,详情请参见基本概念>表。
Tunnel
MaxCompute的数据通道,提供高并发的离线数据上传下载服务。您可以使用Tunnel服务向MaxCompute批量上传数据或者将数据下载。相关命令请参见Tunnel命令操作或批量数据通道SDK。
U
UDF
广义的UDF,即User Defined Function,MaxCompute提供的Java编程接口开发自定义函数,详情请参见用户指南>UDF。
狭义的UDF指用户自定义标量值函数(User Defined Scalar Function),它的输入与输出是一对一的关系,即读入一行数据,写出一条输出值。
UDAF
User Defined Aggregation Function,自定义聚合函数,它的输入与输出是多对一的关系, 即将多条输入记录聚合成一条输出值。可以与SQL中的Group By语句联用。详情请参见Java UDF>UDAF。
UDTF
User Defined Table Valued Function,自定义表值函数,用来解决一次函数调用输出多行数据的场景,也是唯一能返回多个字段的自定义函数。而UDF只能一次计算输出一条返回值。详情请参见Java UDF>UDAF。
MaxCompute小文件有关场景及解决方案
KB: 84446 ·
更新时间:2018-07-30 13:48:26
本页目录
问题症状
问题原因
解决方案
更多信息
相关文章
问题症状
您在使用MaxCompute Java SDK的Tunnel传输数据的时候,有时会发现数据传输等待的时间很长,语句的执行性能不好。遇到这种情况,可能是因为您的MaxCompute小文件过多,从而影响性能。
问题原因
小文件产生的场景有很多,请参考下文:更多信息。
解决方案
您可以通过以下的命令来查看表中的小文件数量:
试用
desc extended + 表名
您尝试执行下面的SQL语句来整合小文件:
试用
set odps.merge.cross.paths=true;
set odps.merge.max.partition.count=100; --默认优化10个分区,此时设置为优化100个分区。
ALTER TABLE 表名[partition] MERGE SMALLFILES;
更多信息
背景信息
MaxCompute使用的Pangu分布式文件系统是按块BLOCK存放,一般的,文件大小比块大小小的文件(默认块大小为64M),叫做小文件。
目前MaxCompute有以下场景可以产生小文件:
Reduce计算过程会产生大量小文件;
Tunnel数据采集过程中会生成小文件;
Job执行过程中生成的各种临时文件、回收站保留的过期的文件等,主要分类为:
TABLE_BACKUP:回收站中超过保留天数的表
FUXI_JOB_TMP:作业运行临时目录
TMP_TABLE:作业运行中产生的临时表
INSTANCE:作业运行时保留在meta表中的日志
LIFECYCLE:超过生命周期的的数据表或分区
INSTANCEPROFILE:作业提交及执行完成后的profile信息
VOLUME_TMP:没有meta信息,但在pangu上有路径的数据
TEMPRESOURCE:用户自定义函数使用的一次性临时资源文件
FAILOVER:系统发生failover时保留的临时文件
问题影响
小文件过多会带来以下影响:
影响Fuxi 启动map instance,默认情况下一个小文件对应一个instance,造成浪费资源,影响整体的执行性能。
过多的小文件给pangu 文件系统带来压力,且影响空间的有效利用,严重的会直接导致pangu不可服务。
处理方式
不同原因产生的小文件,需要有不同的处理方法:
Reduce过程中产生的小文件
您需要使用insert overwrite源表(或分区)即可,或者写入到新表删除源表。
Tunnel数据采集过程中产生的小文件
调用Tunnel SDK时,当buffer达到64MB时提交一次;
使用console时避免频繁上传小文件,建议积累较大时一次性上传;
如果导入的是分区表,建议给分区设置生命周期,过期不用的数据自动清理;
Insert overwrite源表(或分区);
ALTER合并模式,通过console命令进行合并:
试用
ALTER TABLE tablename [PARTITION] MERGE SMALLFILES;
临时表
您在用临时表建议创建时都加上生命周期,到期后垃圾回收自动回收;
血缘信息上下游表的相关信息,多久会更新?为什么会有重名?使用DataWorks提交任务时,${bdp.system.bizdate}这个时间,如果想取一年前、一个月前、半年前和一周前分别怎么操作?如何删除MaxCompute项目客户端运行odpscmd -f cmd_file,cmd_file中能有变量吗?有类似ptkill之类的方法批量kill超时任务的方式吗?mapjoin中大表和小表是否可以互换位置?如何通过MaxCompute做分布式处理并访问外网?MaxCompute客户端配置因本地时间不对导致超时如何在客户端上查看任务信息?MaxCompute支持快照吗?changelog的设置方式是什么?ODPS中可以设置表的过期时间,是否有办法设置分区的过期时间?MaxCompute会有lock-in问题吗?MaxCompute是否支持restful接口?运维中心补数据功能怎么使用?新建子管理账号,但子账号不能访问MaxCompute的功能,是什么原因?将开通数据保护的MaxCompute表数据导入另一项目空间如何查看某个MaxCompute项目及每张数据表所使用的磁盘空间?如何调用Package中的表?项目Owner能否更换为子账号?MaxCompute页面“运行任务”一类的栏目功能在哪里能看到?
MaxCompute SQL基本区别
主要区别 问题现象 解决办法
应用场景 不支持事务(没有 commit 和 rollback,不推荐使用 Insert Into)
建议代码具有等幂性支持重跑,推荐 Insert Overwrite 写入数据。
不支持索引和主外键约束 -
不支持自增字段和默认值 如果有默认值,请在数据写入时自行赋值。
表分区 单表支持 6 万个分区 -
一次查询输入的分区不能超过1万,否则执行会报错;另外如果是 2 级分区且查询时只根据 2 级分区进行过滤,总的分区数大于 1 万也可能导致报错 一次查询输入的分区数不能大于 1 万
一次查询输出的分区数不能大于2048
精度 DOUBLE类型存在精度问题 不建议在关联时候进行直接等号关联两个DOUBLE字段,推荐的做法是把两个数做减法,如果差距小于一个预设的值就认为是相同,比如 abs(a1- a2) < 0.000000001。
目前产品上已经支持高精度的类型DECIMAL 如果有更高精度要求的,可以先把数据存为 STRING类型,然后使用 UDF来实现对应的计算。
数据类型转换 各种预期外的错误,代码维护问题。 如果有2个不同的字段类型需要做Join,建议您先把类型转好后再Join。
日期型和字符串的隐式转换 在需要传入日期型的函数里如果传入一个字符串,字符串和日期类型的转换根据yyyy-mm-dd hh:mi:ss格式进行转换。
其他格式转换 日期函数 > TO_DATE
DDL与DML的区别及解法
主要区别 问题现象 解决办法
表结构 不能修改分区列列名,只能修改分区列对应的值。 分区和分区列的区别
支持增加列,但是不支持删除列以及修改列的数据类型。 SQL常见问题
INSERT 语法上最直观的区别是:Insert into/overwrite 后面有个关键字Table。 -
数据插入表的字段映射不是根据Select的别名做的,而是根据Select的字段的顺序和表里的字段的顺序。 -
UPDATE/DELETE 目前不支持Update/Delete语句。 更新和删除数据
SELECT 输入表的数量不能超过16张 -
一个非分组列同一个Group By Key中的数据有多条,不使用聚合函数的话就没办法展示 Group by查询中的Select字段,应是Group By的分组字段,或者需要使用聚合函数。
子查询 子查询必须要有别名 建议查询不要带别名
IN/NOT IN In/Not In,Exist/Not Exist,后面的子查询数据量不能超过 1000 条 如何使用Not In
如果业务上已经保证了子查询返回结果的唯一性,可以考虑去掉Distinct,从而提升查询性能。
SQL返回10000条 MaxCompute限制了单独执行Select语句时返回的数据条数 其他操作
需要查询的结果数据条数很多 如何获取所有数据
MAPJOIN Join不支持笛卡尔积 Join必须要用on设置关联条件
如果有一些小表需要做广播表,需要用 Mapjoin Hint
如何解决Join报错
ORDER BY Order By后面需要配合Limit n使用 如果希望做很大的数据量的排序,甚至需要做全表排序,可以把这个N设置的很大
MaxCompute 查询数据的排序
UNION ALL 参与UNION ALL运算的所有列的属性不同,抛异常 参与UNION ALL运算的所有列的数据类型、列个数、列名称必须完全一致
UNION ALL查询外面需要再嵌套一层子查询 -
快速掌握SQL写法
更新时间:2019-01-23 00:43:03
编辑 ·
· 我的收藏
本页目录
数据集准备
SQL操作
本文通过课程实践的方式,为您介绍MaxCompute SQL,让您快速掌握SQL的写法,并清楚MaxCompute SQL和标准SQL的区别,请结合 MaxCompute SQL 基础文档 进行阅读。
数据集准备
这里选择大家比较熟悉的Emp/Dept表做为数据集。为方便大家操作,特提供相关的 MaxCompute建表语句和数据文件(emp表数据文件,dept表数据文件),您可自行在MaxCompute项目上创建表并上传数据。
创建emp表的DDL语句,如下所示:
试用
CREATE TABLE IF NOT EXISTS emp (
EMPNO string ,
ENAME string ,
JOB string ,
MGR bigint ,
HIREDATE datetime ,
SAL double ,
COMM double ,
DEPTNO bigint );
创建 dept 表的 DDL 语句,如下所示:
试用
CREATE TABLE IF NOT EXISTS dept (
DEPTNO bigint ,
DNAME string ,
LOC string);
SQL操作
初学SQL常遇到的问题点
使用Group by,那么Select的部分要么是分组项,要么就得是聚合函数。
Order by后面必须加Limit n。
Select表达式中不能用子查询,可以改写为Join。
Join不支持笛卡尔积,以及MapJoin的用法和使用场景。
Union all需要改成子查询的格式。
In/Not in语句对应的子查询只能有一列,而且返回的行数不能超过1000,否则也需要改成Join。
编写SQL进行解题
题目一:列出至少有一个员工的所有部门。
为了避免数据量太大的情况下导致 常遇问题点 中的第6点,您需要使用Join 进行改写。如下所示:
试用
SELECT d.*
FROM dept d
JOIN (
SELECT DISTINCT deptno AS no
FROM emp
) e
ON d.deptno = e.no;
题目二:列出薪金比SMITH多的所有员工。
MapJoin的典型场景,如下所示:
试用
SELECT /*+ MapJoin(a) */ e.empno
, e.ename
, e.sal
FROM emp e
JOIN (
SELECT MAX(sal) AS sal
FROM `emp`
WHERE `ENAME` = 'SMITH'
) a
ON e.sal > a.sal;
题目三:列出所有员工的姓名及其直接上级的姓名。
非等值连接,如下所示:
试用
SELECT a.ename
, b.ename
FROM emp a
LEFT OUTER JOIN emp b
ON b.empno = a.mgr;
题目四:列出最低薪金大于1500的各种工作。
Having 的用法,如下所示:
试用
SELECT emp.`JOB`
, MIN(emp.sal) AS sal
FROM `emp`
GROUP BY emp.`JOB`
HAVING MIN(emp.sal) > 1500;
题目五:列出在每个部门工作的员工数量、平均工资和平均服务期限。
时间处理上有很多好用的内建函数,如下所示:
试用
SELECT COUNT(empno) AS cnt_emp
, ROUND(AVG(sal), 2) AS avg_sal
, ROUND(AVG(datediff(getdate(), hiredate, 'dd')), 2) AS avg_hire
FROM `emp`
GROUP BY `DEPTNO`;
题目六: 列出每个部门的薪水前3名的人员的姓名以及他们的名次(Top n的需求非常常见)。
SQL 语句如下所示:
试用
SELECT *
FROM (
SELECT deptno
, ename
, sal
, ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC) AS nums
FROM emp
) emp1
WHERE emp1.nums < 4;
题目七: 用一个SQL写出每个部门的人数、CLERK(办事员)的人数占该部门总人数占比。
SQL语句如下所示:
试用
SELECT deptno
, COUNT(empno) AS cnt
, ROUND(SUM(CASE
WHEN job = 'CLERK' THEN 1
ELSE 0
END) / COUNT(empno), 2) AS rate
FROM `EMP`
GROUP BY deptno;
修改不兼容SQL实战
更新时间:2019-01-23 00:50:07
编辑 ·
· 我的收藏
本页目录
group.by.with.star
bad.escape
column.repeated.in.creation
string.join.double
window.ref.prev.window.alias
select.invalid.token.after.star
agg.having.ref.prev.agg.alias
order.by.no.limit
generated.column.name.multi.window
non.boolean.filter
post.select.ambiguous
duplicated.partition.column
order.by.col.ambiguous
in.subquery.without.result
ctas.if.not.exists
worker.restart.instance.timeout
divide.nan.or.overflow
small.table.exceeds.mem.limit
sigkill.oom
wm_concat.first.argument.const
pt.implicit.convertion.failed
having.use.select.alias
dynamic.pt.to.static
lot.not.in.subquery
MaxCompute 开发团队近期已经完成了 MaxCompute2.0 灰度升级。新升级的版本完全拥抱开源生态,支持更多的语言功能,带来更快的运行速度,同时新版本会执行更严格的语法检测,以致于一些在老编译器下正常执行的不严谨的语法 case 在 MaxCompute2.0 下会报错。
为了使 MaxCompute2.0 灰度升级更加平滑,MaxCompute 框架支持回退机制,如果 MaxCompute2.0 任务失败,会回退到 MaxCompute1.0 执行。回退本身会增加任务 E2E 时延。鼓励大家提交作业之前,手动关闭回退set odps.sql.planner.mode=lot;以避免 MaxCompute 框架回退策略修改对大家造成影响。
MaxCompute 团队会根据线上回退情况,邮件或者钉钉等通知有问题任务的 Owner,请大家尽快完成 SQL 任务修改,否则会导致任务失败。烦请大家仔细 check 以下报错情况,进行自检,以免通知遗漏造成任务失败。
下面列举常见的一些会报错的语法:
group.by.with.star
SELECT * …GROUP BY… 的问题。
旧版 MaxCompute 中,即使 * 中覆盖的列不在 group by key 内,也支持 select * from group by key 的语法,但 MaxCompute2.0 和 Hive 兼容,并不允许这种写法,除非 group by 列表是所有源表中的列。示例如下:
场景一:group by key 不包含所有列
错误写法:
试用
SELECT * FROM t GROUP BY key;
报错信息:
试用
FAILED: ODPS-0130071:[1,8] Semantic analysis exception - column reference t.value should appear in GROUP BY key
正确改法:
试用
SELECT DISTINCT key FROM t;
场景二:group by key 包含所有列
不推荐写法:
试用
SELECT * FROM t GROUP BY key, value; -- t has columns key and value
虽然 MaxCompute2.0 不会报错,但推荐改为:
试用
SELECT DISTINCT key, value FROM t;
bad.escape
错误的 escape 序列问题。
按照 MaxCompute 文档的规定,在 string literal 中应该用反斜线加三位8进制数字表示从 0 到 127 的 ASCII 字符,例如:使用 \001, \002 表示 0,1 等。但目前\01,\0001 也被当作 \001 处理了。
这种行为会给新用户带来困扰,比如需要用 “\0001” 表示 “\000” + “1”,便没有办法实现。同时对于从其他系统迁移而来的用户而言,会导致正确性错误。
说明 \000后面在加数字,如 \0001 - \0009或 \00001的写法可能会返回错误。
MaxCompute2.0 会解决此问题,需要 script 作者将错误的序列进行修改,示例如下:
错误写法:
试用
SELECT split(key, "\01"), value like "\0001" FROM t;
报错信息:
试用
FAILED: ODPS-0130161:[1,19] Parse exception - unexpected escape sequence: 01
ODPS-0130161:[1,38] Parse exception - unexpected escape sequence: 0001
正确改法:
试用
SELECT split(key, "\001"), value like "\001" FROM t;
column.repeated.in.creation
create table 时列名重复的问题。
如果 create table 时列名重复,MaxCompute2.0 将会报错,示例如下:
错误写法:
试用
CREATE TABLE t (a BIGINT, b BIGINT, a BIGINT);
报错信息:
试用
FAILED: ODPS-0130071:[1,37] Semantic analysis exception - column repeated in creation: a
正确改法:
试用
CREATE TABLE t (a BIGINT, b BIGINT);
string.join.double
写 JOIN 条件时,等号的左右两边分别是 String 和 Double 类型。
出现上述情况,旧版 MaxCompute 会把两边都转成 Bigint,但会导致严重的精度损失问题,例如:1.1 = “1” 在连接条件中会被认为是相等的。但 MaxCompute2.0 会与 Hive 兼容转为 Double。
不推荐写法:
试用
SELECT * FROM t1 JOIN t2 ON t1.double_value = t2.string_value;
warning 信息:
试用
WARNING:[1,48] implicit conversion from STRING to DOUBLE, potential data loss, use CAST function to suppress
推荐改法:
试用
select * from t1 join t2 on t.double_value = cast(t2.string_value as double);
除以上改法外,也可使用用户期望的其他转换方式。
window.ref.prev.window.alias
Window Function 引用同级 Select List 中的其他 Window Function Alias 的问题。
示例如下:
如果 rn 在 t1 中不存在,错误写法如下:
试用
SELECT row_number() OVER (PARTITION BY c1 ORDER BY c1) rn,
row_number() OVER (PARTITION by c1 ORDER BY rn) rn2
FROM t1;
报错信息:
试用
FAILED: ODPS-0130071:[2,45] Semantic analysis exception - column rn cannot be resolved
正确改法:
试用
SELECT row_number() OVER (PARTITION BY c1 ORDER BY rn) rn2
FROM
(
SELECT c1, row_number() OVER (PARTITION BY c1 ORDER BY c1) rn
FROM t1
) tmp;
select.invalid.token.after.star
select * 后面接 alias 的问题。
Select 列表里面允许用户使用 * 代表选择某张表的全部列,但 * 后面不允许加 alias(即使 * 展开之后只有一列也不允许),新一代编译器将会对类似语法进行报错,示例如下:
错误写法:
试用
select * as alias from dual;
报错信息:
试用
FAILED: ODPS-0130161:[1,10] Parse exception - invalid token 'as'
正确改法:
试用
select * from dual;
agg.having.ref.prev.agg.alias
有 Having 的情况下,Select List 可以出现前面 Aggregate Function Alias 的问题。示例如下:
错误写法:
试用
SELECT count(c1) cnt,
sum(c1) / cnt avg
FROM t1
GROUP BY c2
HAVING cnt > 1;
报错信息:
试用
FAILED: ODPS-0130071:[2,11] Semantic analysis exception - column cnt cannot be resolved
ODPS-0130071:[2,11] Semantic analysis exception - column reference cnt should appear in GROUP BY key
其中 s、cnt 在源表 t1 中都不存在,但因为有 HAVING,旧版 MaxCompute 并未报错,MaxCompute2.0 则会提示 column cannot be resolve,并报错。
正确改法:
试用
SELECT cnt, s, s/cnt avg
FROM
(
SELECT count(c1) cnt,
sum(c1) s
FROM t1
GROUP BY c2
HAVING count(c1) > 1
) tmp;
order.by.no.limit
ORDER BY 后没有 LIMIT 语句的问题。
MaxCompute 默认 order by 后需要增加 limit 限制数量,因为 order by 是全量排序,没有 limit 时执行性能较低。示例如下:
错误写法:
试用
select * from (select *
from (select cast(login_user_cnt as int) as uv, '3' as shuzi
from test_login_cnt where type = 'device' and type_name = 'mobile') v
order by v.uv desc) v
order by v.shuzi limit 20;
报错信息:
试用
FAILED: ODPS-0130071:[4,1] Semantic analysis exception - ORDER BY must be used with a LIMIT clause
正确改法:
在子查询 order by v.uv desc 中增加 limit。
另外,MaxCompute1.0 对于 view 的检查不够严格。比如在一个不需要检查 LIMIT 的 Projec(odps.sql.validate.orderby.limit=false)中,创建了一个 View:
试用
CREATE VIEW dual_view AS SELECT id FROM dual ORDER BY id;
若访问此 View:
试用
SELECT * FROM dual_view;
MaxCompute1.0 不会报错,而 MaxCompute2.0 会报如下错误信息:
试用
FAILED: ODPS-0130071:[1,15] Semantic analysis exception - while resolving view xdj.xdj_view_limit - ORDER BY must be used with a LIMIT clause
generated.column.name.multi.window
使用自动生成的 alias 的问题。
旧版 MaxCompute 会为 Select 语句中的每个表达式自动生成一个 alias,这个 alias 会最后显示在 console 上。但是,它并不承诺这个 alias 的生成规则,也不承诺这个 alias 的生成规则会保持不变,所以不建议用户使用自动生成的 alias。
MaxCompute2.0 会对使用自动生成 alias 的情况给予警告,由于牵涉面较广,暂时无法直接给予禁止。
对于某些情况,MaxCompute 的不同版本间生成的 alias 规则存在已知的变动,但因为已有一些线上作业依赖于此类 alias,这些查询在 MaxCompute 版本升级或者回滚时可能会失败,存在此问题的用户,请修改您的查询,对于感兴趣的列,显式地指定列的别名。示例如下:
不推荐写法:
试用
SELECT _c0 FROM (SELECT count(*) FROM dual) t;
建议改法:
试用
SELECT c FROM (SELECT count(*) c FROM dual) t;
non.boolean.filter
使用了非 boolean 过滤条件的问题。
MaxCompute 不允许布尔类型与其他类型之间的隐式转换,但旧版 MaxCompute 会允许用户在某些情况下使用 Bigint 作为过滤条件。MaxCompute2.0 将不再允许,如果您的脚本中存在这样的过滤条件,请及时修改。示例如下:
错误写法:
试用
select id, count(*) from dual group by id having id;
报错信息:
试用
FAILED: ODPS-0130071:[1,50] Semantic analysis exception - expect a BOOLEAN expression
正确改法:
试用
select id, count(*) from dual group by id having id <> 0;
post.select.ambiguous
在 order by、 cluster by、 distribute by、sort by 等语句中,引用了名字冲突的列的问题。
旧版 MaxCompute 中,系统会默认选取 Select 列表中的后一列作为操作对象,MaxCompute2.0 将会进行报错,请及时修改。示例如下:
错误写法:
试用
select a, b as a from t order by a limit 10;
报错信息:
试用
FAILED: ODPS-0130071:[1,34] Semantic analysis exception - a is ambiguous, can be both t.a or null.a
正确改法:
试用
select a as c, b as a from t order by a limit 10;
本次推送修改会包括名字虽然冲突但语义一样的情况,虽然不会出现歧义,但是考虑到这种情况容易导致错误,作为一个警告,希望用户进行修改。
duplicated.partition.column
在 query 中指定了同名的 partition 的问题。
旧版 MaxCompute 在用户指定同名 partition key 时并未报错, 而是后一个的值直接覆盖了前一个,容易产生混乱。MaxCompute2.0 将会对此情况进行报错,示例如下:
错误写法一:
试用
insert overwrite table partition (ds = '1', ds = '2')select ... ;
实际上,在运行时 ds = ‘1’ 被忽略。
正确改法:
试用
insert overwrite table partition (ds = '2')select ... ;
错误写法二:
试用
create table t (a bigint, ds string) partitioned by (ds string);
正确改法:
试用
create table t (a bigint) partitioned by (ds string);
order.by.col.ambiguous
Select list 中 alias 重复,之后的 Order by 子句引用到重复的 alias 的问题。
错误写法:
试用
SELECT id, id
FROM dual
ORDER BY id;
正确改法:
试用
SELECT id, id id2
FROM dual
ORDER BY id;
需要去掉重复的 alias,Order by 子句再进行引用。
in.subquery.without.result
colx in subquery 没有返回任何结果,则 colx 在源表中不存在的问题。
错误写法:
试用
SELECT * FROM dual
WHERE not_exist_col IN (SELECT id FROM dual LIMIT 0);
报错信息:
试用
FAILED: ODPS-0130071:[2,7] Semantic analysis exception - column not_exist_col cannot be resolved
ctas.if.not.exists
目标表语法错误问题。
如果目标表已经存在,旧版 MaxCompute 不会做任何语法检查,MaxCompute2.0 则会做正常的语法检查,这种情况会出现很多错误信息,示例如下:
错误写法:
试用
CREATE TABLE IF NOT EXISTS dual
AS
SELECT * FROM not_exist_table;
报错信息:
试用
FAILED: ODPS-0130131:[1,50] Table not found - table meta_dev.not_exist_table cannot be resolved
worker.restart.instance.timeout
旧版 MaxCompute UDF 每输出一条记录,便会触发一次对分布式文件系统的写操作,同时会向 Fuxi 发送心跳,如果 UDF 10 分钟没有输出任何结果,会得到如下错误提示:
试用
FAILED: ODPS-0123144: Fuxi job failed - WorkerRestart errCode:252,errMsg:kInstanceMonitorTimeout, usually caused by bad udf performance.
MaxCompute2.0 的 Runtime 框架支持向量化,一次会处理某一列的多行来提升执行效率。但向量化可能导致原来不会报错的语句(2 条记录的输出时间间隔不超过 10 分钟),因为一次处理多行,没有及时向 Fuxi 发送心跳而导致 timeout。
遇到这个错误,建议首先检查 UDF 是否有性能问题,每条记录需要数秒的处理时间。如果无法优化 UDF 性能,可以尝试手动设置 batch row 大小来绕开(默认为1024):
试用
set odps.sql.executionengine.batch.rowcount=16;
divide.nan.or.overflow
旧版 MaxCompute 不会做除法常量折叠的问题。
比如如下语句,旧版 MaxCompute 对应的物理执行计划如下:
试用
EXPLAIN
SELECT IF(FALSE, 0/0, 1.0)
FROM dual;
In Task M1_Stg1:
Data source: meta_dev.dual
TS: alias: dual
SEL: If(False, Divide(UDFToDouble(0), UDFToDouble(0)), 1.0)
FS: output: None
由此可以看出,IF 和 Divide 函数仍然被保留,运行时因为 IF 第一个参数为 false,第二个参数 Divide 的表达式不需要求值,所以不会出现除零异常。
而 MaxCompute2.0 则支持除法常量折叠,所以会报错。如下所示:
错误写法:
试用
SELECT IF(FALSE, 0/0, 1.0)
FROM dual;
报错信息:
试用
FAILED: ODPS-0130071:[1,19] Semantic analysis exception - encounter runtime exception while evaluating function /, detailed message: DIVIDE func result NaN, two params are 0.000000 and 0.000000
除了上述的 nan,还可能遇到 overflow 错误,比如:
错误写法:
试用
SELECT IF(FALSE, 1/0, 1.0)
FROM dual;
报错信息:
试用
FAILED: ODPS-0130071:[1,19] Semantic analysis exception - encounter runtime exception while evaluating function /, detailed message: DIVIDE func result overflow, two params are 1.000000 and 0.000000
正确改法:
建议去掉 /0 的用法,换成合法常量。
CASE WHEN 常量折叠也有类似问题,比如:CASE WHEN TRUE THEN 0 ELSE 0/0,MaxCompute2.0 常量折叠时所有子表达式都会求值,导致除0错误。
CASE WHEN 可能涉及更复杂的优化场景,比如:
试用
SELECT CASE WHEN key = 0 THEN 0 ELSE 1/key END
FROM (
SELECT 0 AS key FROM src
UNION ALL
SELECT key FROM src) r;
优化器会将除法下推到子查询中,转换类似于:
试用
M (
SELECT CASE WHEN 0 = 0 THEN 0 ELSE 1/0 END c1 FROM src
UNION ALL
SELECT CASE WHEN key = 0 THEN 0 ELSE 1/key END c1 FROM src) r;
报错信息:
试用
FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed: java.lang.ArithmeticException: DIVIDE func result overflow, two params are 1.000000 and 0.000000
其中 UNION ALL 第一个子句常量折叠报错,建议将 SQL 中的 CASE WHEN 挪到子查询中,并去掉无用的 CASE WHEN 和去掉/0用法:
试用
SELECT c1 END
FROM (
SELECT 0 c1 END FROM src
UNION ALL
SELECT CASE WHEN key = 0 THEN 0 ELSE 1/key END) r;
small.table.exceeds.mem.limit
旧版 MaxCompute 支持 Multi-way Join 优化,多个 Join 如果有相同 Join Key,会合并到一个 Fuxi Task 中执行,比如下面例子中的 J4_1_2_3_Stg1:
试用
EXPLAIN
SELECT t1.*
FROM t1 JOIN t2 ON t1.c1 = t2.c1
JOIN t3 ON t1.c1 = t3.c1;
旧版 MaxCompute 物理执行计划:
试用
In Job job0:
root Tasks: M1_Stg1, M2_Stg1, M3_Stg1
J4_1_2_3_Stg1 depends on: M1_Stg1, M2_Stg1, M3_Stg1
In Task M1_Stg1:
Data source: meta_dev.t1
In Task M2_Stg1:
Data source: meta_dev.t2
In Task M3_Stg1:
Data source: meta_dev.t3
In Task J4_1_2_3_Stg1:
JOIN: t1 INNER JOIN unknown INNER JOIN unknown
SEL: t1._col0, t1._col1, t1._col2
FS: output: None
如果增加 MapJoin hint,旧版 MaxCompute 物理执行计划不会改变。也就是说对于旧版 MaxCompute 优先应用 Multi-way Join 优化,并且可以忽略用户指定 MapJoin hint。
试用
EXPLAIN
SELECT /*+mapjoin(t1)*/ t1.*
FROM t1 JOIN t2 ON t1.c1 = t2.c1
JOIN t3 ON t1.c1 = t3.c1;
旧版 MaxCompute 物理执行计划同上。
MaxCompute2.0 Optimizer 会优先使用用户指定的 MapJoin hint,对于上述例子,如果 t1 比较大的话,会遇到类似错误:
试用
FAILED: ODPS-0010000:System internal error - SQL Runtime Internal Error: Hash Join Cursor HashJoin_REL… small table exceeds, memory limit(MB) 640, fixed memory used …, variable memory used …
对于这种情况,如果 MapJoin 不是期望行为,建议去掉 MapJoin hint。
sigkill.oom
同 small.table.exceeds.mem.limit,如果用户指定了 MapJoin hint,并且用户本身所指定的小表比较大。在旧版 MaxCompute 下有可能被优化成 Multi-way Join 从而成功。但在 MaxCompute2.0 下,用户可能通过设定 odps.sql.mapjoin.memory.max 来避免小表超限的错误,但每个 MaxCompute worker 有固定的内存限制,如果小表本身过大,则 MaxCompute worker 会由于内存超限而被杀掉,错误类似于:
试用
Fuxi job failed - WorkerRestart errCode:9,errMsg:SigKill(OOM), usually caused by OOM(outof memory).
这里建议您去掉 MapJoin hint,使用 Multi-way Join。
wm_concat.first.argument.const
聚合函数中关于 WM_CONCAT 的说明,一直要求 WM_CONCAT 第一个参数为常量,旧版 MaxCompute 检查不严格,比如源表没有数据,就算 WM_CONCAT 第一个参数为 ColumnReference,也不会报错。
试用
函数声明:
string wm_concat(string separator, string str)
参数说明:
separator:String类型常量,分隔符。其他类型或非常量将引发异常。
MaxCompute2.0,会在 plan 阶段便检查参数的合法性,假如 WM_CONCAT 的第一个参数不是常量,会立即报错。示例如下:
错误写法:
试用
SELECT wm_concat(value, ',') FROM src GROUP BY value;
报错信息:
试用
FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed: com.aliyun.odps.lot.cbo.validator.AggregateCallValidator$AggregateCallValidationException: Invalid argument type - The first argument of WM_CONCAT must be constant string.
pt.implicit.convertion.failed
srcpt 是一个分区表,并有两个分区:
试用
CREATE TABLE srcpt(key STRING, value STRING) PARTITIONED BY (pt STRING);
ALTER TABLE srcpt ADD PARTITION (pt='pt1');
ALTER TABLE srcpt ADD PARTITION (pt='pt2');
对于以上 SQL,String 类型 pt 列 IN INT 类型常量,都会转为 Double 进行比较。即使 Project 设置了 odps.sql.udf.strict.mode=true,旧版 MaxCompute 不会报错,所有 pt 都会过滤掉,而 MaxCompute2.0 会直接报错。示例如下:
错误写法:
试用
SELECT key FROM srcpt WHERE pt IN (1, 2);
报错信息:
试用
FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed: java.lang.NumberFormatException: ODPS-0123091:Illegal type cast - In function cast, value 'pt1' cannot be casted from String to Double.
建议避免 String 分区列和 INT 类型常量比较,将 INT 类型常量改成 String 类型。
having.use.select.alias
SQL 规范定义 Group by + Having 子句是 Select 子句之前阶段,所以 Having 中不应该使用 Select 子句生成的 Column alias,示例如下:
错误写法:
试用
SELECT id id2 FROM DUAL GROUP BY id HAVING id2 > 0;
报错信息:
试用
FAILED: ODPS-0130071:[1,44] Semantic analysis exception - column id2 cannot be resolvedODPS-0130071:[1,44] Semantic analysis exception - column reference id2 should appear in GROUP BY key
其中 id2 为 Select 子句中新生成的 Column alias,不应该在 Having 子句中使用。
dynamic.pt.to.static
MaxCompute2.0 动态分区某些情况会被优化器转换成静态分区处理,示例如下:
试用
INSERT OVERWRITE TABLE srcpt PARTITION(pt) SELECT id, 'pt1' FROM dual;
会被转化成
试用
INSERT OVERWRITE TABLE srcpt PARTITION(pt='pt1') SELECT id FROM dual;
如果用户指定的分区值不合法,比如错误的使用了’${bizdate}’,MaxCompute2.0 语法检查阶段便会报错。详情请参见分区 。
错误写法:
试用
INSERT OVERWRITE TABLE srcpt PARTITION(pt) SELECT id, '${bizdate}' FROM dual LIMIT 0;
报错信息:
试用
FAILED: ODPS-0130071:[1,24] Semantic analysis exception - wrong columns count 2 in data source, requires 3 columns (includes dynamic partitions if any)
旧版 MaxCompute 因为 LIMIT 0,SQL 最终没有输出任何数据,动态分区不会创建,所以最终不报错。
lot.not.in.subquery
In subquery 中 null 值的处理问题。
在标准 SQL 的 IN 运算中,如果后面的值列表中出现 null,则返回值不会出现 false,只可能是 null 或者 true。如 1 in (null, 1, 2, 3) 为 true,而 1 in (null, 2, 3) 为 null,null in (null, 1, 2, 3) 为 null。同理 not in 操作在列表中有 null 的情况下,只会返回 false 或者 null,不会出现 true。
MaxCompute2.0 会用标准的行为进行处理,收到此提醒的用户请注意检查您的查询,IN 操作中的子查询中是否会出现空值,出现空值时行为是否与您预期相符,如果不符合预期请做相应的修改。示例如下:
试用
select * from t where c not in (select accepted from c_list);
若 accepted 中不会出现 null 值,则此问题可忽略。若出现空值,则 c not in (select accepted from c_list) 原先返回 true,则新版本返回 null。
正确改法:
试用
select * from t where c not in (select accepted from c_list where accepted is not null)
分区剪裁合理性评估
更新时间:2018-07-18 11:44:53
编辑 ·
· 我的收藏
本页目录
背景及目的
问题示例
判断分区剪裁是否生效
分区剪裁失效的场景分析
影响及思考
背景及目的
MaxCompute的 分区表 是指在创建表时指定分区空间,即指定表内的某几个字段作为分区列。使用数据时,如果指定了需要访问的分区名称,则只会读取相应的分区,避免全表扫描,提高处理效率,降低费用。
分区剪裁是指对分区列指定过滤条件,使得 SQL 执行时只用读取表的部分分区数据,避免全表扫描引起的数据错误及资源浪费。看起来非常简单,但是实际上经常会出现分区失效的情况,本文将通过示例为您介绍一些常见问题的解决方案。
问题示例
测试表 test_part_cut 的分区,如下图所示:
执行以下 SQL 代码:
试用
select count(*)
from test_part_cut
where ds= bi_week_dim('20150102');
--其中为bi_week_dim自定义函数:返回格式为 (年,第几周):
--如果是正常日期,判断日期是所传入参数中年份所属周,以周四为一周的起始日期,如果碰到20140101因为属于周三所以算在2013年最后一周返回2013,52。而20150101则返回是2015,1。
--如果是类似20151231是周四又恰逢与20160101在同一周,则返回2016,1。
bi_week_dim(‘20150102’)的返回结果是 2015,1,不符合表 test_part_cut 的分区值,通常我们会认为上面的 SQL 不会读任何分区,而实际情况却是 该 SQL 读了表 test_part_cut 的所有分区,LogView 如下图所示:
从上图可以看出,该 SQL 在执行的时候读取了表 test_part_cut 的所有分区。
由上述示例可见,分区剪裁使用尽管简单,但也容易出错。因此,本文将从以下两方面进行介绍:
判断 SQL 中分区剪裁是否生效。
了解常见的导致分区剪裁失效的场景。
判断分区剪裁是否生效
通过 explain 命令查看 SQL 的执行计划,用于发现 SQL 中的分区剪裁是否生效。
分区剪裁未生效的效果。
试用
explain
select seller_id
from xxxxx_trd_slr_ord_1d
where ds=rand();
看上图中红框的内容,表示读取了表 xxxxx_trd_slr_ord_1d 的 1344 个分区,即该表的所有分区。