MSCK REPAIR TABLE在幕后做了什么,为什么它如此缓慢?

18

我知道MSCK REPAIR TABLE可以更新外部表的元数据,使其包含当前分区。

要做到这一点,您只需要在表的根目录上执行ls命令(假设该表只按一个列进行分区),并获取所有分区,这通常是一个不到1秒的操作。

但实际上,这个操作可能需要很长时间才能执行完毕(甚至可能在AWS Athena上超时)。

那么我的问题是,MSCK REPAIR TABLE背后实际上做了什么以及为什么?

MSCK REPAIR TABLE如何找到分区?


如果相关的话,还有一些额外的数据:

我们的数据都在S3上,无论是在EMR(Hive)还是Athena(Presto)上运行时都很慢,表中有大约450个分区,每个分区平均有90个文件,每个分区总共3GB,文件格式为Apache parquet格式。


https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL提到了`ALTER TABLE RECOVER PARTITIONS。它只是MSCK`的别名,还是做更少的工作? - Piotr Findeisen
@PiotrFindeisen 看起来只是 EMR 的等效命令。 - gdoron
据我所知,它列出了所有的分区文件并收集了一些关于它们的元数据。如果你有450个分区和每个分区90个文件,那么它可能会执行40500次调用来逐个获取每个文件的大小。我不确定它是否还做了其他事情,但如果是的话,它可能也会对文件进行一些统计分析。如果是这种情况,你可以尝试使用这个选项:SET hive.stats.autogather=false;需要多长时间才能完成?我们是指几分钟还是几小时?几分钟的时间不会让我感到惊讶。 - FurryMachine
1个回答

24
你说得没错,它会读取目录结构,将其分成分区,然后更新hive元数据仓库。事实上,最近改进了该命令以从元数据仓库中删除不存在的分区。你提供的示例非常简单,因为它只有一个级别的分区键。考虑具有多个分区键的表(在实践中通常有2-3个分区键)。msck repair需要对表目录下的所有子目录进行完整的树遍历,解析文件名,确保文件名有效,检查分区是否已经存在于元数据仓库中,然后添加未出现在元数据仓库中的分区。请注意,文件系统上的每个列表都是对名称节点(在HDFS的情况下)的RPC或对S3或ADLS的Web服务调用,这可能需要相当长的时间。另外,为了确定分区是否已经存在于元数据仓库中,它需要对元数据仓库知道的表的所有分区进行完整的列出。这两个步骤都有可能增加对大型表的命令所需的时间。自Hive 2.3.0以来,msck repair表的性能得到了显著改善(有关更多详细信息,请参见HIVE-15879)。您可以调整hive.metastore.fshandler.threadshive.metastore.batch.retrieve.max以提高命令的性能。

谢谢!不过我很好奇,即使在我的表中只有1列的情况下,分区操作为什么还要花费这么长时间?从阅读源代码来看,似乎只需要读取第一层,也就是仅有的450个文件(目录)。 - gdoron
其实你是对的。msck在一个大于分区数的级别上进行了不必要的列出操作。这可以得到改进。我已经为此创建了HIVE-21040。 - Vihang
非常感谢您通过源代码进行验证,找到并打开了Jira!如果您能更新您的答案,那就太好了,因为大多数人不会费心阅读评论... - gdoron
4
值得注意的是,MSCK REPAIR 可以添加新分区路径,但不能执行相反的操作:如果之前存在的分区路径被删除,则运行 MSCK REPAIR 无法起到删除分区的效果;这必须手动完成。此外,参见这个常见陷阱。 - y2k-shubham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接