Spark2.4.x与Spark3.3.x版本在SQL队列的差异对比
DLI整理了Spark2.4.x与Spark3.3.x版本在SQL队列的差异,便于您了解Spark版本升级后SQL队列上运行的作业在适配新版本引擎时的影响。
histogram_numeric函数的返回值的类型不同
- 说明:
Spark SQL中的histogram_numeric函数返回一个结构体数组(x,y),不同版本的引擎x的类型不同。
- Spark2.4.x:Spark 3.2或更早版本中,x为double类型。
- Spark3.3.x:x类型等于函数输入值的类型。
- 升级引擎版本后是否对作业有影响:
有影响,涉及相关用法需要适配。
- 示例代码:
准备数据:
create table test_histogram_numeric(val int); INSERT INTO test_histogram_numeric VALUES(1),(5),(8),(6),(7),(9),(8),(9);
执行sql:
select histogram_numeric(val,3) from test_histogram_numeric;
- Spark2.4.5
[{"x":1.0,"y":1.0},{"x":5.5,"y":2.0},{"x":8.166666666666666,"y":5.0}]
- Spark3.3.1
[{"x":1,"y":1.0},{"x":5,"y":2.0},{"x":8,"y":5.0}]
- Spark2.4.5
Spark3.3.x不再支持使用“0$”指定第一个参数
- 说明:
format_string(strfmt, obj, ...) 和 printf(strfmt, obj, ...) 中的 strfmt 将不再支持使用“0$”指定第一个参数,第一个参数应始终由“1$”引用当使用参数索引来指示参数在参数列表中的位置。
- Spark2.4.x:%0和%1均可表示第一个参数。
- Spark3.3.x:不再支持%0。
- 升级引擎版本后是否对作业有影响:
有影响,请作业中如涉及使用%0需修改以适配Spark3.3.x。
- 示例代码1:
执行sql:
SELECT format_string('Hello, %0$s! I\'m %1$s!', 'Alice', 'Lilei');
- Spark2.4.5
Hello, Alice! I'm Alice!
- Spark3.3.1
DLI.0005: The value of parameter(s) 'strfmt' in `format_string` is invalid: expects %1$, %2$ and so on, but got %0$.
- Spark2.4.5
- 示例代码2:
执行sql:
SELECT format_string('Hello, %1$s! I\'m %2$s!', 'Alice', 'Lilei');
- Spark2.4.5
Hello, Alice! I'm Lilei!
- Spark3.3.1
Hello, Alice! I'm Lilei!
- Spark2.4.5
Spark3.3.x版本中空字符串无引号。
- 说明:
默认情况下,空值在CSV数据源中,2.4.5版本空字符串为"",升级到spark3.3.1后空字符串无引号。
- Spark2.4.x:空值在CSV数据源中为""。
- Spark3.3.x:空值在CSV数据源中无引号。
如需在Spark3.3.x版本中恢复Spark2.4.x的格式,可以通过设置spark.sql.legacy.nullValueWrittenAsQuotedEmptyStringCsv为 true来实现。
- 升级引擎版本后是否对作业有影响:
有影响,导出orc文件中null值存储形式不同。
- 示例代码:
准备数据:
create table test_null(id int,name string) stored as parquet; insert into test_null values(1,null);
导出csv查看文件内容
- Spark2.4.5
1,""
- Spark3.3.1
1,
- Spark2.4.5
describe function返回结果不同
- 说明:
如果function不存在,describe function会执行失败。
- Spark2.4.x:DESCRIBE函数仍然可以运行并打印“Function:func_name not found”
- Spark3.3.x:函数不存在的提示信息变更为失败。
- 升级引擎版本后是否对作业有影响:
有影响,describe function 相关API的返回信息不同。
- 示例代码:
执行sql:
describe function dli_no(dli_no不存在)
返回信息明确告知不支持指定表外部属性
- 说明:
表外部属性`external`变为保留。如果指定外部属性,某些命令将执行失败。
- Spark2.4.x:通过 `CREATE TABLE ... TBLPROPERTIES`和`ALTER TABLE ... SET TBLPROPERTIES`指定external属性,命令执行成功,但实际上external属性被静默忽略,表依然是managed table。
- Spark3.3.x:
通过 `CREATE TABLE ... TBLPROPERTIES`和`ALTER TABLE ... SET TBLPROPERTIES`指定external属性,命令将会失败。
如需在Spark3.3.x版本中恢复Spark2.4.x的使用方式,可以通过设置spark.sql.legacy.notReserveProperties为 true来实现。
- 升级引擎版本后是否对作业有影响:
有影响,涉及相关用法需要适配。
- 示例代码:
执行sql:
CREATE TABLE test_external(id INT,name STRING) TBLPROPERTIES('external'=true);
新增支持解析“+Infinity”、“+INF”和“-INF”类型字符串的值
- 说明:
- Spark2.4.x:当从定义为FloatType 或 DoubleType的JSON属性读取值时,Spark2.4.x仅支持解析“Infinity”和“-Infinity”。
- Spark3.3.x:当从定义为FloatType 或 DoubleType的JSON属性读取值时,Spark3.3.x除了支持解析“Infinity”和“-Infinity”之外,还支持解析字符串“+Infinity”、“+INF”和“-INF”。
- 升级引擎版本后是否对作业有影响:
功能增强,无影响
默认配置spark.sql.adaptive.enabled=true
- 说明:
- Spark2.4.x:在Spark 2.4.x版本中,默认情况下spark.sql.adaptive.enabled配置项的值是false,即自适应查询执行(Adaptive Query Execution,简称AQE)特性是关闭的。
- Spark3.3.x:从Spark3.3.x-320版本起开始默认开启AQE特性,即spark.sql.adaptive.enabled配置项的值是true。
- 升级引擎版本后是否对作业有影响:
DLI功能增强,spark.sql.adaptive.enabled的默认参数值发生变化。
SHOW TABLES输出的schema的变化
- 说明:
SHOW TABLES的输出schema从database: string变成了namespace: string。
- Spark2.4.x:SHOW TABLES的输出schema是database: string。
- Spark3.3.x:
SHOW TABLES的输出schema从database: string变成了namespace: string。
其中对于内置catalog,namespace字段被命名为database;对于v2 catalog没有isTemporary字段。
如果你希望在Spark 3.3.x版本中恢复到Spark 2.4.x版本的样式,可以通过将spark.sql.legacy.keepCommandOutputSchema设置为true来实现。
- 升级引擎版本后是否对作业有影响:
有影响,请排查作业中与SHOW TABLES有关的使用方法,并按上述说明适配新版本的使用要求。
- 示例代码:
执行sql:
show tables;
- Spark2.4.5
database tableName isTemporary db1 table1 false
- Spark3.3.1
namespace tableName isTemporary db1 table1 false
- Spark2.4.5
SHOW TABLE EXTENDED输出的schema变化
- 说明:
SHOW TABLE EXTENDED的输出schema从database: string变成了namespace: string。
- 升级引擎版本后是否对作业有影响:
有影响,请排查作业中与SHOW TABLES有关的使用方法,并按上述说明适配新版本的使用要求。
- 示例代码:
执行sql:
show table extended like 'table%';
- Spark2.4.5
database tableName isTemporary information db1 table1 false Database:db1...
- Spark3.3.1
namespace tableName isTemporary information db1 table1 false Database:db1...
- Spark2.4.5
表刷新对依赖项缓存的影响
- 说明:
升级Spark3.3.x版本后表刷新会清除表的缓存数据,但保持依赖项缓存。
- Spark2.4.x:在Spark 2.4.x版本中,当执行表刷新操作(如REFRESH TABLE)时,不会保留依赖项(例如视图)的缓存数据。
ALTER TABLE .. ADD PARTITION ALTER TABLE .. RENAME PARTITION ALTER TABLE .. DROP PARTITION ALTER TABLE .. RECOVER PARTITIONS MSCK REPAIR TABLE LOAD DATA REFRESH TABLE TRUNCATE TABLE spark.catalog.refreshTable
- Spark3.3.x:升级Spark3.3.x版本后表刷新会清除表的缓存数据,但保持依赖项缓存。
- Spark2.4.x:在Spark 2.4.x版本中,当执行表刷新操作(如REFRESH TABLE)时,不会保留依赖项(例如视图)的缓存数据。
- 升级引擎版本后是否对作业有影响:
升级新版本引擎后会增加原有依赖项的缓存数据。
表刷新对依赖该表的其他缓存操作的影响
- 说明:
- Spark2.4.x:Spark2.4.x中,刷新表时,只有当表本身被缓存时,才会触发引用该表的所有其他缓存的uncache操作。
- Spark3.3.x:升级新版本引擎后不管表本身是否有缓存,只要刷新表,那么依赖该表的其他缓存都会执行uncache操作。
- 升级引擎版本后是否对作业有影响:
DLI功能增强,保证表刷新操作能对缓存生效,提高程序健壮性。
ADD PARTITION新增支持使用类型化文字
- 说明:
- Spark2.4.x:
在Spark 2.4.x版本中,使用ADD PARTITION时,如果使用类型化文字(例如date'2020-01-01'),分区值会被解析为字符串值date'2020-01-01',会生成一个非法的日期值,因此会添加一个值为null的分区。
正确的做法是使用字符串值,例如ADD PARTITION(dt = '2020-01-01')
- Spark3.3.x:在Spark 3.3.x版本中,对分区操作支持使用类型化文字,支持使用ADD PARTITION(dt = date'2020-01-01'),并且可以正确地将分区值解析为日期类型,而不是字符串。
- Spark2.4.x:
- 升级引擎版本后是否对作业有影响:
有影响,ADD PARTITION中对于类型化文字的处理方式的变化。
- 示例代码:
准备数据:
create table test_part_type (id int,name string,pt date) PARTITIONED by (pt); insert into test_part_type partition (pt = '2021-01-01') select 1,'name1'; insert into test_part_type partition (pt = date'2021-01-01') select 1,'name1';
执行sql:
select id,name,pt from test_part_type; (配置参数spark.sql.forcePartitionPredicatesOnPartitionedTable.enabled为false)
- Spark2.4.5
1 name1 2021-01-01 1 name1
- Spark3.3.1
1 name1 2021-01-01 1 name1 2021-01-01
- Spark2.4.5
DayTimeIntervalType的映射类型变化为Duration
- 说明:
在ArrowWriter和ArrowColumnVector开发者API中,从Spark 3.3.x版本开始,Spark SQL中的DayTimeIntervalType类型被映射到Apache Arrow的Duration类型。
- Spark2.4.x:DayTimeIntervalType被映射到Apache Arrow的Interval类型。
- Spark3.3.x:DayTimeIntervalType被映射到Apache Arrow的Duration类型。
- 升级引擎版本后是否对作业有影响:
有影响,DayTimeIntervalType的映射类型发生变化。
日期差值返回结果的类型变化
- 说明:
date减法表达式(如 date1 - date2)返回DayTimeIntervalType的值
- Spark2.4.x:返回CalendarIntervalType。
- Spark3.3.x:返回DayTimeIntervalType。
恢复之前的行为,将 spark.sql.legacy.interval.enabled 设置为 true
- 升级引擎版本后是否对作业有影响:
有影响,日期差值返回结果默认类型变化。
单位到单位间隔的映射类型的变化
- 说明:
- Spark2.4.x:Spark2.4.x版本中单位到单位的间隔(如 INTERVAL '1-1' YEAR TO MONTH)和单位列表间隔(如 INTERVAL '3' DAYS '1' HOUR)将转换为CalendarIntervalType类型。
- Spark3.3.x:在Spark3.3.x版本中,单位到单位的间隔(如 INTERVAL '1-1' YEAR TO MONTH)和单位列表间隔(如 INTERVAL '3' DAYS '1' HOUR)将转换为 ANSI 间隔类型:YearMonthIntervalType或DayTimeIntervalType类型。
在Spark3.3.x版本中如果希望恢复到Spark2.4.x之前的映射类型,可以通过设置配置项
spark.sql.legacy.interval.enabled为true来实现。
- 升级引擎版本后是否对作业有影响:
有影响,映射后的数据类型发生变化。
timestamps减法表达式返回值类型变化
- 说明:
- Spark2.4.x:timestamps减法表达式,如select timestamp'2021-03-31 23:48:00'- timestamp'2021-01-01 00:00:00'返回CalendarIntervalType类型的值。
- Spark3.3.x:timestamps减法表达式,如select timestamp'2021-03-31 23:48:00'- timestamp'2021-01-01 00:00:00'返回DayTimeIntervalType类型的值。
在Spark3.3.x版本中如果希望恢复到Spark2.4.x之前的映射类型,可以通过设置配置项spark.sql.legacy.interval.enabled为true来实现。
- 升级引擎版本后是否对作业有影响:
有影响,映射后的数据类型发生变化。
不再支持混合使用年月字段和日时间字段
- 说明:
- Spark2.4.x:单位列表间隔文字可以混合使用年月字段(YEAR 和 MONTH)和日时间字段(WEEK、DAY、...、MICROSECOND)。
- Spark3.3.x:单位列表间隔文字不能混合使用年月字段(YEAR 和 MONTH)和日时间字段(WEEK、DAY、...、MICROSECOND)。提示无效输入。
在Spark3.3.x版本中如果希望恢复到Spark2.4.x之前的使用方式,可以通过设置配置项spark.sql.legacy.interval.enabled为true来实现。
- 升级引擎版本后是否对作业有影响:
有影响。
CREATE TABLE .. LIKE .. 命令不能使用保留属性
- 说明:
CREATE TABLE .. LIKE .. 命令不能使用保留属性
- Spark2.4.x:Spark2.4.x版本中在执行CREATE TABLE .. LIKE .. 命令时可以使用保留属性。
例如:TBLPROPERTIES('location'='/tmp') 不会改变表的位置但会创建一个无效属性。
- Spark3.3.x:Spark3.3.x版本中CREATE TABLE .. LIKE .. 命令不能使用保留属性,
例如使用TBLPROPERTIES('location'='/tmp')或TBLPROPERTIES('owner'='yao')会直接失败。
- Spark2.4.x:Spark2.4.x版本中在执行CREATE TABLE .. LIKE .. 命令时可以使用保留属性。
- 升级引擎版本后是否对作业有影响:
有影响。
- 示例代码1:
准备数据:
CREATE TABLE test0(id int, name string); CREATE TABLE test_like_properties LIKE test0 LOCATION 'obs://bucket1/test/test_like_properties';
执行sql:
DESCRIBE FORMATTED test_like_properties;
- 示例代码2:
准备数据:
CREATE TABLE test_like_properties0(id int) using parquet LOCATION 'obs://bucket1/dbgms/test_like_properties0'; CREATE TABLE test_like_properties1 like test_like_properties0 tblproperties('location'='obs://bucket1/dbgms/test_like_properties1');
执行sql:
DESCRIBE FORMATTED test_like_properties1;
- Spark2.4.5
DLI.0005: mismatched input 'tblproperties' expecting {<EOF>, 'LOCATION'}
- Spark3.3.1
The feature is not supported: location is a reserved table property, please use the LOCATION clause to specify it.
- Spark2.4.5
包含自动生成的别名时创建视图失败
- 说明:
- Spark2.4.x:Spark2.4.x版本中如果语句中包含自动生成的别名,则正常执行且无提示信息。
- Spark3.3.x:Spark3.3.x版本中如果语句中包含自动生成的别名,则创建/更改视图将失败。
在Spark3.3.x版本中如果希望恢复到Spark2.4.x之前的使用方式,可以通过设置配置项spark.sql.legacy.allowAutoGeneratedAliasForView为true来实现。
- 升级引擎版本后是否对作业有影响:
有影响。
- 示例代码:
准备数据:
create table test_view_alis(id1 int,id2 int); INSERT INTO test_view_alis VALUES(1,2);
执行sql:
create view view_alis as select id1 + id2 from test_view_alis;
日期加减时间字段间隔后的返回值类型的变化
- 说明:
date +/-只有日期时间字段(如date'2011-11-11')的间隔+间隔12小时返回类型变化。
- Spark2.4.x:在Spark 2.4.x中,当对定义为FloatType或DoubleType的JSON属性进行日期加减操作时,例如date'2011-11-11'加上或减去一个时间间隔(如12小时),返回的类型是日期(DateType)。
- Spark3.3.x:Spark 3.3.x版本中,对于同样的操作,返回的类型变为时间戳(TimestampType),用于保持与Hive的兼容性。
- 升级引擎版本后是否对作业有影响:
有影响。
- 示例代码:
执行sql:
select date '2011-11-11' - interval 12 hour
- Spark2.4.5
2011-11-10
- Spark3.3.1
1320897600000
- Spark2.4.5
Spark SQL支持Char/Varchar类型
- 说明:
- Spark2.4.x:在Spark2.4.x版本中,Spark SQL表字段不支持Char/Varchar类型,当指定为Char/Varchar类型时会强制转换为String类型。
- Spark3.3.x:Spark SQL表字段支持CHAR/CHARACTER和VARCHAR类型。
- 升级引擎版本后是否对作业有影响:
无影响。
- 示例代码:
准备数据:
create table test_char(id int,name varchar(24),name2 char(24));
执行sql:
show create table test_char;
- Spark2.4.5
create table `test_char`(`id` INT,`name` STRING,`name2` STRING) ROW FORMAT...
- Spark3.3.1
create table test_char(id INT,name VARCHAR(24),name2 VARCHAR(24)) ROW FORMAT...
- Spark2.4.5
空值分区的查询语句不同
- 说明:
- Spark2.4.x:
Spark 3.0.1或更早版本中,如果分区列是字符串类型,则将其解析为其文本表示形式的字符串文本,例如字符串“null”。
通过part_col='null'查询空值分区的数据。
- Spark3.3.x:
`PARTITION(col=null)`始终在分区规范中解析为null,即使分区列是字符串类型。
通过part_col is null查询空值分区的数据。
- Spark2.4.x:
- 升级引擎版本后是否对作业有影响:
有影响,涉及对空值分区的查询需要适配
- 示例代码:
准备数据:
CREATE TABLE test_part_null (col1 INT, p1 STRING) USING PARQUET PARTITIONED BY (p1); INSERT INTO TABLE test_part_null PARTITION (p1 = null) SELECT 0;
执行sql:
select * from test_part_null;
- Spark2.4.5
0 null
Spark2.4.5版本执行select * from test_part_null where p1='null'可查到分区数据。
- Spark3.3.1
0
Spark3.3.1版本执行select * from test_part_null where p1 is null才可查询到数据。
- Spark2.4.5
对分区表数据的处理方式不同
- 说明:
datasourcev1分区外表,路径下已经存在不带uuid的分区路径数据。
执行insert overwrite partition操作,Spark3.3.x会清除之前不带uuid的分区数据,Spark2.4.x不会清理。- Spark2.4.x:
保留不带uuid分区路径下数据。
- Spark3.3.x:
会删除不带uuid分区路径下数据。
- Spark2.4.x:
- 升级引擎版本后是否对作业有影响:
有影响,会清理脏数据。
- 示例代码:
准备数据:
obs://bucket1/test/overwrite_datasource下创建pt=pt1目录,并移入一个parquet数据问题
create table overwrite_datasource(id int,name string,pt string) using parquet PARTITIONED by(pt) LOCATION 'obs://bucket1/test/overwrite_datasource'; SELECT * FROM overwrite_datasource1 where pt='pt1'两个版本均查询不到数据。
执行sql:
insert OVERWRITE table overwrite_datasource partition(pt='pt1') values(2,'aa2');
导出CSV文件时保留特殊字符的引号
- 说明:
- Spark2.4.x:
在Spark 2.4.x版本中,导出CSV文件时,如果字段值中包含特殊字符如换行符(\n)和回车符(\r),并且这些特殊字符被引号(例如双引号")包围,Spark会自动处理这些引号,在导出的CSV文件中舍弃这些引号。
例如,字段值"a\rb"在导出时不会包含引号。
- Spark3.3.x:
在Spark 3.3.x版本中,优化了对于CSV文件的导出处理,如果字段值中包含特殊字符,并且这些特殊字符被引号包围,Spark会保留这些引号。
例如:字段值"a\rb"在导出时,引号仍被保留在最终的CSV文件中。
- Spark2.4.x:
- 升级引擎版本后是否对作业有影响:
对查询结果无影响,但导出文件样式有影响。
- 示例代码:
准备数据:
create table test_null2(str1 string,str2 string,str3 string,str4 string); insert into test_null2 select "a\rb", null, "1\n2", "ab";
执行sql:
SELECT * FROM test_null2;
- Spark2.4.5
a b 1 2 ab
- Spark3.3.1
a b 1 2 ab
导出查询结果到obs,查看csv文件内容:
- Spark2.4.5
a b,"","1 2",ab
- Spark3.3.1
"a b",,"1 2",ab
- Spark2.4.5
新增支持自适应Skip partial agg功能的配置
- 说明:
Spark3.3.x版本中新增支持自适应Skip partial agg功能,即当Partial Agg效果不佳时,可以直接跳过,避免Partial Agg带来的额外性能消耗。相关参数:
- spark.sql.aggregate.adaptivePartialAggregationEnabled:用于控制是否启用自适应Skip partial agg功能。当设置为true时,Spark会根据运行时的统计数据动态决定是否跳过部分聚合。
- spark.sql.aggregate.adaptivePartialAggregationInterval:该参数用于配置分析间隔,即在处理了多少行数据之后,Spark会进行一次分析,用来决定是否需要跳过部分聚合。
- spark.sql.aggregate.adaptivePartialAggregationRatio:该参数是判断是否跳过的阈值,用于判断“已处理的group分组/已处理的行数”的比例。如果这个比例大于配置的阈值,则认为预聚合效果不好,此时Spark可以选择跳过部分聚合,避免进一步的性能损失。
在使用时系统先按照spark.sql.aggregate.adaptivePartialAggregationInterval配置的间隔进行分析,当处理的行数到达间隔之后,再计算”已处理的group分组/已处理的行数”,如果比例大于配置的阈值,则认为预聚合效果不好,此时可以直接选择跳过。
- 升级引擎版本后是否对作业有影响:
DLI功能增强。
新增支持Parallel Multi-Insert
- 说明:
Spark3.3.x版本中新增支持Parallel Multi-Insert,如果SQL存在multi-insert的场景,在同一个SQL里插入到多个表中,这类SQL在Spark开源本身是串行处理的,性能受到制约。针对这类SQL,Spark3.3.x版本中DLI新增支持multi-insert并行化的优化处理,可以让所有的insert都并发执行,提升处理性能。
在使用时需配置开启以下功能开关(默认关闭):
spark.sql.lazyExecutionForDDL.enabled=true
spark.sql.parallelMultiInsert.enabled=true
- 升级引擎版本后是否对作业有影响:
DLI功能增强,增强multi-insert并行化特性,提升作业运行的可靠性。
新增支持Enhance Reuse Exchange
- 说明:
Spark3.3.x版本中新增支持Enhance Reuse Exchange,SQL的对应plan存在sort merge join可重用的条件,通过打开相应开关spark.sql.execution.enhanceReuseExchange.enabled,可以实现SMJ plan node重用。
在使用时需配置开启以下功能开关(默认关闭):
spark.sql.execution.enhanceReuseExchange.enabled=true
- 升级引擎版本后是否对作业有影响:
DLI功能增强。