【问题标题】:How to manually add partition details into hive metastore tables?如何手动将分区详细信息添加到配置单元元存储表中?
【发布时间】:2021-09-24 19:42:22
【问题描述】:

在我的 HDFS 中,我按 dateevent_id 对数据进行了分区,并且拥有大约 140 万个 parquet 文件。今天,为了分析 Apache Spark 中的数据,我使用spark.read.parquet("/path/to/root/")。列出文件大约需要 30 分钟,我每次都必须这样做,而且越来越烦人。

现在,我想设置一个外部表,使用 MySQL 作为 Hive Metastore。我目前面临一个已知问题,即发现所有 1.4 分区需要永远。众所周知,MSCK REPAIR TABLE my_table 不存在。相反,我生成了一个长查询(大约 400 MB),其中包含这样的查询


ALTER TABLE my_table ADD 
  PARTITION (date = 'YYYY-MM-DD', event_id = "<some value>") LOCATION ''
  PARTITION (date = 'YYYY-MM-DD', event_id = "<some value>") LOCATION ''
  PARTITION (date = 'YYYY-MM-DD', event_id = "<some value>") LOCATION ''
  ...
  PARTITION (date = 'YYYY-MM-DD', event_id = "<some value>") LOCATION ''
  PARTITION (date = 'YYYY-MM-DD', event_id = "<some value>") LOCATION ''

已经3个小时了,它仍然只处理了不到100,000个分区。我观察到一些事情:

  1. Spark 一次执行一个分区。
  2. Spark 似乎会检查每条路径是否存在。

所有这些都会增加运行时间。我已经搜索过,但无法找到如何禁用这两个操作。

所以,我想针对 Hive 元存储的 MySQL 数据库和表手动执行 SQL 操作,以创建和管理表。我看过但无法弄清楚如何手动管理这些表。请问,有人知道怎么做吗?具体来说,我想要以下内容:

  1. 如何通过直接进入 Hive 元存储表来创建带有分区的外部表?
  2. 如何通过对 Hive 元存储表进行直接 upsert 查询来管理外部表分区?

有没有什么好的资源可以用来了解元存储中的后备表。我觉得手动插入会快得多。谢谢。

【问题讨论】:

  • 谁拥有“分区”?蜂巢?还是 MySQL?在 MySQL 中,分区很少能提高性能。向我们展示表结构。
  • @RickJames,我想我不明白你的问题。我生成并分区镶木地板文件。我想使用 hive 元存储来跟踪表和分区信息。

标签: mysql apache-spark hadoop hive hive-metastore


【解决方案1】:

我认为这里的核心问题是你有太多的分区。分区通常应在低基数列上进行(与记录总数相比,不同值的数量相对较少)。通常,您宁愿选择较少数量的大文件,而不是大量的小文件。

在您的示例中,date 可能是一个很好的分区列,假设每个日期都有很多记录。如果event_id 有大量不同的值,则不适合进行分区。只需将其保留为未分区的列即可。

对高基数列进行分区的替代方法是分桶。这会将分桶列的相似值分组,因此它们位于同一个文件中,但不会将每个值拆分到单独的文件中。 AWS Athena docs 对这个概念有很好的了解。

【讨论】:

  • 如果一个外部表(另一个创建文件的进程)如何通知 Spark 数据文件被分桶...也就是说,每个文件都包含特定 @ 的数据987654324@? (记住 event_id 的不同数量会有所不同)另外,Spark 是否为每个存储桶索引 event_id 的值? MSCK REPAIR 会这样做吗?
  • @ThatGuy Bucketing 是一种性能优化,可以帮助避免某些情况下的数据混洗,但它增加了一些复杂性。在走这条路之前,我会尝试将 event_id 保留为每条记录中的常规列(不是分区列),看看是否可以将小文件合并为更少的大文件。
  • event_date + event_id 的给定分区中的每个文件大约是 1GB parquet 文件,所以不是很小的文件。我可以尝试重新生成在event_date(每个文件夹)上分区的文件,然后在event_id 上进行分桶(日期内的每个文件都针对特定的event_id)。如果我这样做了,Spark 如何知道给定存储桶中的 event_id
  • 分桶模式是表元数据的一部分。这里的想法是使连接更有效:在一个公共(桶)键上连接两个表意味着它提前知道哪些文件包含记录。但是您可能不需要,我会尝试删除 event_id 分区并将其保留为常规列。分区就像一个索引,如果每个文件只有一个分区,那么它就达不到目的了。
  • 分桶模式是表元数据的一部分。”是什么意思?如果我在 spark 中创建一个外部表,将其指向包含我的 parquet 文件的文件夹,Spark 是否会进行初始扫描以确定每个文件的 event_id 的值是多少? (假设我存储桶,每个文件只包含特定event_id的值)此外,“如果每个文件有一个分区,那么它有点违背目的,你的意思是什么? >"?
【解决方案2】:

这可能是统计信息自动收集的问题。作为一种解决方法,请在恢复分区之前关闭 hive.stats.autogather。

  1. 关闭统计信息自动收集:

    set hive.stats.autogather=false;

  2. 运行 MSCK REPAIR 或 ALTER TABLE RECOVER PARTITIONS。

如果您需要更新统计信息,您可以仅对新分区单独执行 ANALYZE。

相关票证为HIVE-18743HIVE-19489HIVE-17478

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多