分区表查询条件使用浅析

时间:2024-03-28 16:04:01

很多同学已经跨入了MaxCompute的殿堂,对分区表和非分区表有了初步了解,也充分意识到“大数据量”的信息表要尽可能的采用分区方式,因为这样在查询、统计、分析的时候,在WHERE条件中可以利用分区列进行过滤,从而提升查询效率,减少不必要的计算开销。有细心的同学就会将问题引申:如果有个分区表,分区列为ABC三列,我要查询B列为某些值的数据,MaxCompute还能充分发挥分区表的优势吗?答案是肯定的,MaxCompute依然能发挥分区列的优势!在底层解析SQL执行计划时,只会将符合条件的分区纳入计算,而不是进行全表扫描。接下来我们用MaxCompute提供的工具来分析下相关SQL的执行效果。

一、数据准备

实验中使用的数据保存在文件《测试分区列过滤.csv》中,共27条记录,分区列为ABC三列。从分区(a=a1,b=b1,c=c1)到分区(a=a3,b=b3,c=c3)共27个分区,每个分区中有1条数据。

分区表查询条件使用浅析 

实验数据最终要插入到分区表中,因为Tunnel工具不支持直接将数据导入到分区表,所以我们要通过一个“类似结构”的非分区表搭桥——先将文件中的数据导入到一个非分区表中,然后再使用动态SQL将非分区表的数据插入到分区表中。接下来进行具体操作:

1.创建中间数据表

DataWorks的【数据开发】中【新建脚本文件】,然后执行下面的建表SQL语句:

-- 创建对应的非分区表

CREATE TABLE temp_test_wfq(

  bh BIGINT COMMENT '编号',

  bt STRING COMMENT '标题',

  a STRING COMMENT '分区列A',

  b STRING COMMENT '分区列B',

  c STRING COMMENT '分区列C'

) COMMENT '测试分区列过滤_无分区' LIFECYCLE 30;

2.将实验数据导入表【temp_test_wfq】中

将文件《测试分区列过滤.csv》中的样例数据导入中间数据表【temp_test_wfq】中。详细操作参见阿里云官方文档导入本地数据,本文不再赘述。

3.创建实验使用的分区表

DataWorks的【数据开发】中【新建脚本文件】,然后执行下面的建表SQL语句:

-- 创建分区表,分区列为ABC3

CREATE TABLE temp_test(

  bh BIGINT COMMENT '编号',

  bt STRING COMMENT '标题'

) COMMENT '测试分区列过滤'

PARTITIONED BY (

  a STRING COMMENT '分区列A',

  b STRING COMMENT '分区列B',

  c STRING COMMENT '分区列C'

) LIFECYCLE 30;

4.使用动态SQL将非分区表中的数据插入到分区表中

在前面操作中,已经将数据导入到了非分区表中,接下来使用动态SQL语句,将非分区表中的数据迁移到分区表中,具体SQL如下:

-- 使用动态SQL,将非分区表中的数据插入到分区表

INSERT OVERWRITE TABLE temp_test PARTITION (a,b,c)

  SELECT * FROM temp_test_wfq

;

5.确认实验数据已准确插入到分区表中

DataWorks的【数据开发】中【新建脚本文件】,然后执行下面的建表SQL语句:

-- 查询数据表【temp_test】中的数据

SELECT * FROM temp_test ORDER BY bh LIMIT 100;

返回结果应该有27条数据,如下图所示:

分区表查询条件使用浅析

二、测试分区列过滤

 

为了能够看到SQL的执行计划,需要使用EXPLAIN命令来进行展现分析结果,具体SQL语句如下:

-- 解释SQL

EXPLAIN SELECT * FROM (

SELECT * FROM temp_test WHERE a = 'a1'                  --SQL1:M1_Stg1

UNION ALL

SELECT * FROM temp_test WHERE b = 'b2'                  --SQL2:M2_Stg1

UNION ALL

SELECT * FROM temp_test WHERE c = 'c3'                  --SQL3:M3_Stg1

UNION ALL

SELECT * FROM temp_test WHERE b = 'b1' AND c = 'c2'        --SQL4:M4_Stg1

UNION ALL

SELECT * FROM temp_test WHERE a = 'a3' AND c = 'c1' AND bt LIKE '%b2%'    --SQL5:M5_Stg1

) a;

EXPLAINSQL语句,是将5个子查询的结果UNION后,统一返回一个结果集。最终解释执行计划如下图所示:

分区表查询条件使用浅析分区表查询条件使用浅析

1.Job0解读

上面的EXPLAIN结果我们逐段展开解释:

分区表查询条件使用浅析

上图中包含了2部分信息:1.job0 is root job】表示该查询语句只转换为了1个作业,所以只有一条关于“job0”的作业信息。2.In Job job0】后续描述了该作业包含的ROOT任务有“M1_Stg1, M4_Stg1, M2_Stg1, M3_Stg1, M5_Stg1”,共5个。

2.Task M1_Stg1解读

In Task M1_Stg1】对应的内容,则详细阐释了此任务的执行语义:

分区表查询条件使用浅析 

Data source】说明了,该任务的数据源自数据表test_create_projecta.temp_test9个分区,也就是说参与本次运算的数据为这9个分区的数据。仔细观察,还会发现所列出的分区,a列对应的值都是“a1”。

TS】块说明对表“temp_test”进行了“TableScanOperator”操作,SQL语句中对应的部分就是“FROM temp_test”。

FIL】块说明了对数据进行等值过滤,SQL语句相当于“WHERE temp_test.a = 'a1'”。

SEL】块说明了返回的结果数据列,有5列:temp_test.bh, temp_test.bt, temp_test.a, temp_test.b, temp_test.c

UNION】块说明还要跟后续的【SEL】块的查询结果进行UNION操作。

FS】块说明进行最终的输出表操作,因为本条SQL语句没有将结果输出到具体表中,所以输出的目标为“None”。

通过以上分析,该TASK对应的SQL应该是子查询SQL1SELECT * FROM temp_test WHERE a = 'a1'”,最终分区列过滤发挥了作用,参与运算的有9个分区。

3.Task M2_Stg1解读

分区表查询条件使用浅析

Data source】说明了,该任务的数据源自数据表test_create_projecta.temp_test9个分区,也就是说参与本次运算的数据为这9个分区的数据。仔细观察,还会发现所列出的分区,b列对应的值都是“b2”。

TS】块说明对表“temp_test”进行了“TableScanOperator”操作,SQL语句中对应的部分就是“FROM temp_test”。

FIL】块说明了对数据进行等值过滤,SQL语句相当于“WHERE temp_test.b = 'b2'”。

SEL】块说明了返回的结果数据列,有5列:temp_test.bh, temp_test.bt, temp_test.a, temp_test.b, temp_test.c

UNION】块说明还要跟后续的【SEL】块的查询结果进行UNION操作。

FS】块说明进行最终的输出表操作,因为本条SQL语句没有将结果输出到具体表中,所以输出的目标为“None”。

通过以上分析,该TASK对应的SQL应该是子查询SQL1SELECT * FROM temp_test WHERE b = 'b2'”,最终分区列B的过滤条件也发挥了作用,只有(b = 'b2')的9个分区参与了运算。

另外3TASK,感兴趣的同学也可以自己深入分析一下,相信对分区列的过滤查询会有更深刻体会。

三、小结

通过上述实验,我们可以直观的看到,分区表进行查询时,WHERE条件中对分区列进行了等值过滤,会很有效的避免了全表参与运算。MaxCompute在解释SQL时,会只将符合条件的分区数据,纳入到运算里面来,从而显著提升了计算效率,节省了运算成本。