简介
使用spark 2.3进行hive表修改分区信息是,会造成hive元数据的create_time置为0。
复现
使用spark执行ALTER TABLE PARTITION
spark.sql("""ALTER TABLE test.test PARTITION (sdate='2021-12-24') RENAME TO PARTITION (sdate='2021-12-25')""")
执行后,partitions表里的create_time置为0
同样的,使用ANALYZE TABLE test.test PARTITION (sdate='2021-12-24') COMPUTE STATISTICS
分析分区数据,也会造成create_time为0.
原因
执行sparkSession.sessionState.catalog.alterPartitions(tableName: TableIdentifier, parts: Seq[CatalogTablePartition])
函数,
会调用org.apache.spark.sql.hive.HiveExternalCatalog
的alterPartitions函数
继续调用org.apache.spark.sql.hive.client.HiveClientImpl
的alterPartitions函数,接着调用自己的toHivePartition, 代码如下。
def toHivePartition(
p: CatalogTablePartition,
ht: HiveTable): HivePartition = {
val tpart = new org.apache.hadoop.hive.metastore.api.Partition
val partValues = ht.getPartCols.asScala.map { hc =>
p.spec.get(hc.getName).getOrElse {
throw new IllegalArgumentException(
s"Partition spec is missing a value for column '${hc.getName}': ${p.spec}")
}
}
val storageDesc = new StorageDescriptor
val serdeInfo = new SerDeInfo
p.storage.locationUri.map(CatalogUtils.URIToString(_)).foreach(storageDesc.setLocation)
p.storage.inputFormat.foreach(storageDesc.setInputFormat)
p.storage.outputFormat.foreach(storageDesc.setOutputFormat)
p.storage.serde.foreach(serdeInfo.setSerializationLib)
serdeInfo.setParameters(p.storage.properties.asJava)
storageDesc.setSerdeInfo(serdeInfo)
tpart.setDbName(ht.getDbName)
tpart.setTableName(ht.getTableName)
tpart.setValues(partValues.asJava)
tpart.setSd(storageDesc)
tpart.setParameters(mutable.Map(p.parameters.toSeq: _*).asJava)
new HivePartition(ht, tpart)
}
没有保存create_time和last_access_time。
修复
在spark2.4修复了这个问题。
SPARK-21687
生产上暂时不升级spark,只是在执行alter partition语句之前将create_time手动保存在自己的表里。