Spark SQL和Hive在处理日期/时间上的差异

在使用Hive和Spark-SQL进行日期与时间戳类型比较时,存在意料之外的结果。本文揭示了在不同环境下,date类型与timestamp类型直接比较可能导致的错误,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博主历时三年倾注大量心血创作的《大数据平台架构与原型实现:数据中台建设实战》一书已由知名IT图书品牌电子工业出版社博文视点出版发行,真诚推荐给每一位读者!点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,扫码进入京东手机购书页面!

在这里插入图片描述

 

 

注: 本文使用的环境是:Spark:2.2, Hive: 1.2.1

最近在编写一个SQL的过程中遇到了这样一个陷阱:为了便于工作,SQL的编写是通过一个SQL的IDE环境以Hive JDBC驱动的方式连接到HIVE上去执行的,SQL在HIVE上执行正常,有结果数据返回。但是SQL开发好在程序执行时通过Spark-SQL来运行的,SQL可以成功执行,没有报出任何语法错误,但是没有任何结果数据!在经过仔细查询后,发现问题出现在where条件中对理日期/时间字段的比较上。 以下where字句:

where creation_date >= start_time and creation_date < end_time ....

其中creation_date是date类型,start_time和end_time是timestamp类型。虽然是两种时间类型,但是确实是可以直接比较大小的,人们会默认的转换规则是:对于date类型,如果要与timestamp类型进行比较,会默认在时间部分上补齐"00:00:00.00000000", 但是如果在不显式地指定这种转换下,默认的两个类型间的比较结果如下:

  • 使用原始字面量进比较
SQLHIVE执行结果SPARK-SQL执行结果
select ‘2019-01-01’ < ‘2019-01-01 00:00:00’;truetrue
select ‘2019-01-01’ = ‘2019-01-01 00:00:00’;falsefalse
select ‘2019-01-01’ < ‘2019-01-01 00:00:00’;falsefalse

date类型的’2019-01-01’一定是比timestamp类型的’2019-01-01 00:00:00’要。虽然这有些怪异,但在hive和spark-sql上这一比较是一致的

  • 强制类型转换后进行比较
SQLHIVE执行结果SPARK-SQL执行结果
select cast(‘2019-01-01’ as date) < cast(‘2019-01-01 00:00:00’ as timestamp);falsetrue
select cast(‘2019-01-01’ as date) = cast(‘2019-01-01 00:00:00’ as timestamp);truefalse
select cast(‘2019-01-01’ as date) > cast(‘2019-01-01 00:00:00’ as timestamp);falsefalse

这比较让人更加费解,本质上对于’2019-01-01’和’2019-01-01 00:00:00’两个字面量的类型转换都是它们本来的类型,对于Spark-SQL来说,它保持了和前一个版本以纯字面量比较一致的结果,但Hive的比较结果发生了变化,变成了“默认的那种”结果,这是有问题的。如果我们再一步的比较’2019-01-01’和cast(‘2019-01-01’ as date),那么对于Hive的行为就更加难以理解了:

select '2019-01-01' = cast('2019-01-01' as date);  ->  hive: true, spark-sql: true

总之,Hive在处理date类型与timestamp类型的比较上是有问题的! 结果不符合人们的预期,所以最好的作法是将date类型转化为timestamp之后再进行比较! 像下面这样:

SQLHIVE执行结果SPARK-SQL执行结果
select cast(‘2019-01-01’ as timestamp) < cast(‘2019-01-01 00:00:00’ as timestamp);falsefalse
select cast(‘2019-01-01’ as timestamp) = cast(‘2019-01-01 00:00:00’ as timestamp);truetrue
select cast(‘2019-01-01’ as timestamp) > cast(‘2019-01-01 00:00:00’ as timestamp);falsefalse
### 性能对比分析:Hive on SparkSpark on Hive #### 查询执行效率 Hive on SparkHive 查询引擎的一种实现方式,它将 HiveQL 查询转换为基于 Spark 的任务进行执行,而不是传统的 MapReduce。这种设计使得 Hive on Spark 在执行效率上通常优于 Hive on MapReduce,尤其是在涉及复杂查询大规模数据集的场景中 [^4]。由于 Spark 的内存计算特性,Hive on Spark 能够显著减少磁盘 I/O,从而提升查询性能 [^1]。 Spark on Hive 则是通过 SparkSQL 或 DataFrame API 操作 Hive 表中的数据。SparkSQL 的执行引擎是 Spark 本身,其查询优化器是独立开发的,能够针对特定任务进行优化,例如谓词下推(Predicate Pushdown)列裁剪(Column Pruning)。这些优化机制可以进一步提升查询效率,尤其是在交互式查询实时数据处理场景中表现优异 [^1]。 #### 任务调度与资源管理 Hive on Spark 的任务调度依赖于 Hive 的查询计划生成器,Hive 会将 HiveQL 转换为 Spark 的 DAG(有向无环图)任务,并提交到 Spark 集群执行。这种调度方式保留了 Hive 的查询解析元数据管理能力,但底层的执行效率受限于 Spark 的任务调度能力 [^1]。 Spark on Hive 的任务调度则完全由 Spark 负责,SparkSQL 会直接生成执行计划,并利用 Spark 的 DAG 调度机制进行任务分配。由于 Spark 的调度机制更加高效且灵活,Spark on Hive 在资源利用率任务并行性方面表现更优 [^3]。 #### 元数据管理与兼容性 在 Hive on Spark 中,Hive 通过其自身的 MetaStore 获取元数据信息,这意味着 Hive 的元数据管理仍然是核心部分。Hive on SparkHive 元数据的兼容性较好,能够无缝支持 Hive 的表结构分区机制 [^2]。 Spark on Hive 则是通过 SparkSQL 直接加载 Hive 的元数据信息,这需要在 SparkSession 中启用 Hive 支持(`enableHiveSupport()`)。虽然 SparkSQL 能够兼容大部分 Hive 的元数据特性,但在某些高级功能(如复杂的 Hive UDF)上可能存在兼容性问题 [^3]。 #### 数据处理能力与适用场景 Hive on Spark 更适合传统的数据仓库场景,尤其是那些已经基于 Hive 构建的数据分析系统。由于 Hive on Spark 保留了 Hive 的查询语法元数据管理,企业可以无缝迁移至 Spark 执行引擎,从而提升查询性能 [^1]。 Spark on Hive 更适合交互式查询实时数据处理场景,尤其是那些需要与 Spark 生态系统(如 Spark Streaming、Spark MLlib)深度集成的应用。SparkSQL 的独立查询优化器执行引擎能够提供更高的灵活性性能 [^3]。 #### 调优能力 Hive on Spark 的调优能力与 Hive on MapReduce 类似,许多 Hive 的性能配置参数(如 `hive.auto.convert.join.noconditionaltask.size`)在 Hive on Spark 中仍然适用。然而,由于 Spark 的执行模型与 MapReduce 不同,这些参数的具体行为可能会有所差异Spark on Hive 的调优则主要依赖于 Spark 的配置参数,例如 Executor 内存、任务并行度等。Spark 提供了丰富的调优选项,能够针对不同的工作负载进行精细化调整 [^4]。 ### 示例代码 以下是一个使用 SparkSQL 操作 Hive 表的示例代码: ```python from pyspark.sql import SparkSession # 创建 SparkSession 并启用 Hive 支持 spark = SparkSession.builder \ .appName("Spark on Hive Example") \ .enableHiveSupport() \ .getOrCreate() # 查询 Hive 表 df = spark.sql("SELECT * FROM hive_table") # 显示结果 df.show() # 停止 SparkSession spark.stop() ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Laurence 

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

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

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

打赏作者

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

抵扣说明:

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

余额充值