【大数据】Hive中的模式设计

2023-11-06

Hive中的模式设计

Hive 看上去以及实际行为都像一个关系型数据库,并且 Hive 提供的查询语言也确实和之前使用过的 SQL 语言非常地相似。不过,Hive 实现和使用的方式和传统的关系型数据库是非常不同的。通常用户视图移植关系型数据库中的模式,而事实上 Hive 是反模式的。

1.按天划分表

按天划分表就是一种模式,其通常会在表名中加入一个时间戳。每天一张表的方式在数据库领域是反模式的一种方式,但是因为实际情况下数据集增长的很快,这种方式应用还是比较广泛的。

对于 Hive,这种情况下应该使用分区表。Hive 通过 WHERE 子句中的表达式来选择查询所需要的指定的分区。这样的查询执行效率高,看起来也清晰明了。

CREATE TABLE supply (id int, part string, quantity int)
PARTITIONED BY (int day);
SELECT part, quantity FROM supply
WHERE day >= 20110102 AND day < 20110103 AND quantity < 4;

2.关于分区

Hive 中分区的功能是非常有用的。这是因为 Hive 通常要对输入进行全盘扫描,来满足查询条件。通过创建很多的分区确实可以优化一些查询,但是同时可能会对其他一些重要的查询不利。

HDFS 用于设计存储数百万的大文件,而非数十亿的小文件。使用过多分区可能导致的一个问题就是会创建大量的非必须的 Hadoop 文件和文件夹。一个分区就对应着一个包含有多个文件的文件夹。如果指定的表存在数百个分区,那么可能每天都会创建好几万个文件。如果保持这样的表很多年,那么最终就会超出 NameNode 对系统云数据信息的处理能力。因为 NameNode 必须要将所有的系统文件的元数据信息保存在内存中。虽然每个文件只需要少量字节大小的元数据,但是这样也会限制一个 HDFS 实例所能管理的文件总数的上限。

因此,一个理想的分区方案不应该导致产生太多的分区和文件夹目录,并且每个目录下的文件应该足够得大,应该是文件系统中块大小的若干倍。

按时间范围进行分区是一个比较好的策略。我们可以按不同的时间粒度来确定合适大小的数据积累量。随着时间的推移,分区数量的增长是均匀的,而且每个分区下包含的文件大小至少是文件系统中块大小的数倍。这个平衡可以保持使分区足够大,从而优化一般情况下查询的数据吞吐量。

3.唯一键和标准化

关系型数据库通常使用唯一键、索引和标准化来存储数据集,通常是全部或者大部分存储到内存的。然而,Hive 没有主键或基于序列密钥生成的自增键的概念。

如果可以的话,应避免对非标准化数据进行连接 JOIN 操作。复杂的数据类型,如 arraymapstruct,有助于实现在单行中存储一对多数据。这并不是说不应该进行标准化,但是星型架构类型设计并非最优的。

避免标准化的主要原因是为了最小化磁盘寻道,比如那些通常需要外键关系的情况。非标准化数据允许被扫描或写入到大的、连续的磁盘存储区域,从而优化磁盘驱动器的 I / O 性能。然而,非标准化数据可能导致数据重复,而且有更大的导致数据不一致的风险。

4.同一份数据多种处理

Hive 本身提供了一个独特的语法,它可以从一个数据源产生多个数据聚合,而无需每次聚合都要重新扫描一次。对于大的数据输入集来说,这个优化可以节约非常可观的时间。

INSERT OVERWRITE TABLE sales
SELECT * FROM history WHERE action='purchased';
INSERT OVERWRITE TABLE credits
SELECT * FROM history WHERE action='returned';

上面的查询语法是正确的,不过执行效率低下。而下面这个查询可以达到同样的目的,却只需要扫描 history 表一次就行。

FROM history
INSERT OVERWRITE sales SELECT * WHERE action='purchased'
INSERT OVERWRITE credits SELECT * WHERE action='returned';

5.对于每个表的分区

很多的 ETL 处理过程会涉及到多个处理步骤,而每个步骤可能会产生一个或多个临时表,这些表仅供下一个 job 使用。起先可能会觉得将这些临时表进行分区不是那么有必要的。

不过,想象一下这样的场景:由于查询或者原始数据处理的某个步骤出现问题而导致需要对好几天的输入数据重跑 ETL 过程。这时用户可能就需要执行那些一天执行一次的处理过程,来保证在所有的任务都完成之前,不会有 job 将临时表覆盖重写。

下面这个例子设计了一个名为 distinct_ip_in_logs 的中间表,其会在后续处理步骤中使用到。

$ hive -hiveconf dt=2011-01-01
INSERT OVERWRITE table distinct_ip_in_logs
SELECT distinct(ip) as ip from weblogs
WHERE hit_date='${hiveconf:dt}';
CREATE TABLE state_city_for_day (state string,city string);
INSERT OVERWRITE state_city_for_day
SELECT distinct(state,city) FROM distinct_ip_in_logs
JOIN geodata ON (distinct_ip_in_logs.ip=geodata.ip);

这种方式是有效的,不过当计算某一天的数据时,会导致前一天的数据被 INSERT OVERWRITE 语句覆盖掉。如果同时运行两个这样的实例,用于处理不同日期的数据的话,那么它们就可能会互相影响到对方的结果数据。

一个更具鲁棒性的处理方法是在整个过程中使用分区。这样就不会存在同步问题。同时这样还能带来一个好处,那就是可以允许用户对中间数据按日期进行比较。

hive -hiveconf dt=2011-01-01
INSERT OVERWRITE table distinct_ip_in_logs
PARTITION (hit_date=${dt})
SELECT distinct(ip) as ip from weblogs
WHERE hit_date='${hiveconf:dt}';
CREATE TABLE state_city_for_day (state string,city string)
PARTITIONED BY (hit_date string);
INSERT OVERWRITE table state_city_for_day PARTITION(${hiveconf:df})
SELECT distinct(state,city) FROM distinct_ip_in_logs
JOIN geodata ON (distinct_ip_in_logs.ip=geodata.ip)
WHERE (hit_date='${hiveconf:dt}');

这种方法的一个缺点是,用户将需要管理中间表并删除旧分区,不过这些任务也很容易实现自动化处理。

6.分桶表数据存储

分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区,特别是之前所提到过的要确定合适的划分大小。分桶是将数据集分解成更容易管理的若干部分的另一个技术。

例如,假设有个表的一级分区是 dt,代表日期,二级分区是 user_id,那么这种划分方式可能会导致太多的小分区。回想一下,如果用户是使用动态分区来创建这些分区的话,那么默认情况下,Hive 会限制动态分区可以创建的最大分区数,用来避免由于创建太多的分区导致超过了文件系统的处理能力以及其他一些问题。因此,如下命令可能会执行失败。

CREATE TABLE weblog (url STRING, source_ip STRING)
PARTITIONED BY (dt STRING, user_id INT);
FROM raw_weblog
INSERT OVERWRITE TABLE page_view PARTITION(dt='2012-06-08', user_id)
SELECT server_name, url, source_ip, dt, user_id;

不过如果我们对表 weblog 进行分桶,并使用 user_id 字段作为分桶字段,则字段值会根据用户指定的值进行哈希分发到桶中。同一个 user _id 下的记录通常会存储到同一个桶中。假设用户数要比通数多得多,那么每个桶内就将会包含多个用户的记录。

CREATE TABLE weblog (user_id INT, url STRING, source_ip STRING)
PARTITIONED BY (dt STRING)
CLUSTERED BY (user_id) INTO 96 BUCKETS;

分桶有几个优点。因为桶的数量是固定的,所以它没有数据波动。桶对于抽样再合适不过。如果两个表都是按照 user_id 进行分桶的话,那么 Hive 可以创建一个逻辑上正确的抽样。分桶同时有利于执行高效的 map-side join

7.为表增加列

Hive 允许在原始数据文件之上定义一个模式,而不像很多的数据库那样,要求必须以特定的格式转换和导入数据。这样的分离方式的好处是,当为数据文件增加新的字段时,可以容易地适应表定义的模式。

Hive 提供了 SerDe 抽象,其用于从输入中提取数据。SerDe 同样用于输出数据,尽管输出功能并非经常使用,因为 Hive 主要用于查询。一个 SerDe 通常是从左到右进行解析的,通过指定的分隔符将行分解成列。SerDe 通常是非常宽松的。例如如果某行的字段个数比预期的要少,那么缺少的字段将返回 null。如果某行的字段个数比预期的要多,那么多出的字段将会被省略掉。增加新字段的命令只需要一条 ALTER TABLE ADD COLUMN 命令就可以完成。因为日志格式通常是对已有字段增加更多的信息。
在这里插入图片描述
随着时间的推移,可能会为底层数据增加一个新字段。如下这个例子就是展示为数据新增 user_id 字段的过程。需要注意的是,一些旧的原始数据文件中可能不包含这个字段。

在这里插入图片描述

8.使用列存储表

Hive 通常使用行式存储,不过 Hive 也提供了一个列式 SerDe 来以混合列式格式存储信息。虽然这种格式是可以用于任意类型的数据的,不过对于某些数据集使用这种方式是最优的。

假设有足够多的行,像 state 字段和 age 字段这样的列将会有很多重复的数据。这种类型的数据如果使用列式存储将会非常的好。
在这里插入图片描述
如果表具有非常多的字段,用列式存储也会更好。
在这里插入图片描述

9.(几乎)总是使用压缩

几乎在所有情况下,压缩都可以使磁盘上存储的数据量变小,这样可以通过降低 I / O 来提高查询执行速度。Hive 可以无缝地使用很多压缩类型。不使用压缩唯一令人信服的理由就是产生的数据用于外部系统,或者非压缩格式(例如文本格式)是最兼容的。

但是压缩和解压缩都会消耗 CPU 资源。MapReduce 任务往往是 I / O 密集型的,因此 CPU 开销通常不是问题。不过,对于工作流这样的 CPU 密集型的场景,例如一些机器学习算法,压缩实际上可能会从更多必要的操作中获取宝贵的 CPU 资源,从而降低性能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【大数据】Hive中的模式设计 的相关文章

  • 使用 impala 按范围连接表的有效方法

    我第一个有下表 Range 包括值范围和附加列 row From To Country 1 1200 1500 2 2200 2700 3 1700 1900 4 2100 2150 The From and Toare bigint并且是
  • 使用字符串数组在 Hive 表上加载 CSV 文件

    我正在尝试将 CSV 文件插入 Hive 其中一个字段是 string 数组 这是 CSV 文件 48 Snacks that Power Up Weight Loss Aidan B Prince Health Fitness Trave
  • Sqoop 导出分区的 Hive 表

    我在尝试导出分区的 Hive 表时遇到了一些问题 这是否完全受支持 我尝试用谷歌搜索并找到一张 JIRA 票证 sqoop export connect jdbc mysql localhost testdb table sales exp
  • Hadoop 上的 Sqoop:NoSuchMethodError:com.google.common.base.Stopwatch.createStarted() [重复]

    这个问题在这里已经有答案了 我在 Google Cloud DataProc 上的 hadoop 上运行 sqoop 以通过 Cloud SQL 代理访问 postgresql 但遇到 Java 依赖项错误 INFO First Cloud
  • Spark on Hive SQL 查询错误 NoSuchFieldError: HIVE_STATS_JDBC_TIMEOUT

    针对 Hive 2 1 0 提交 Spark 1 6 0 SQL 应用程序时出现错误 Exception in thread main java lang NoSuchFieldError HIVE STATS JDBC TIMEOUT a
  • 运行 Sqoop 导入和导出时如何找到最佳映射器数量?

    我正在使用 Sqoop 版本 1 4 2 和 Oracle 数据库 运行 Sqoop 命令时 例如这样 sqoop import fs
  • 将 Spark 添加到 Oozie 共享库

    默认情况下 Oozie 共享 lib 目录提供 Hive Pig 和 Map Reduce 的库 如果我想在 Oozie 上运行 Spark 作业 最好将 Spark lib jar 添加到 Oozie 的共享库 而不是将它们复制到应用程序
  • 更改 Hadoop 中的数据节点数量

    如何改变数据节点的数量 即禁用和启用某些数据节点来测试可扩展性 说得更清楚一点 我有4个数据节点 我想一一实验1 2 3 4个数据节点的性能 是否可以只更新名称节点中的从属文件 临时停用节点的正确方法 创建一个 排除文件 这列出了您想要删除
  • 无法在 Windows 10 中启动 Spark Master

    我是 Spark 新手 我正在尝试手动启动 master 在 Windows 10 中使用 MINGW64 当我这样做时 Downloads spark 1 5 1 bin hadoop2 4 spark 1 5 1 bin hadoop2
  • 将 Apache Zeppelin 连接到 Hive

    我尝试将我的 apache zeppelin 与我的 hive 元存储连接起来 我使用 zeppelin 0 7 3 所以没有 hive 解释器 只有 jdbc 我已将 hive site xml 复制到 zeppelin conf 文件夹
  • Hadoop-reducer 如何获取数据?

    据我所知 映射器为每个减速器生成 1 个分区 减速器如何知道要复制哪个分区 假设有 2 个节点运行用于字数统计程序的映射器 并且配置了 2 个缩减器 如果每个映射节点生成 2 个分区 并且两个节点中的分区都可能包含相同的单词作为键 那么减速
  • Mapreduce shuffle 阶段出现内存不足错误

    我在运行时遇到奇怪的错误类似字数统计映射缩减程序 我有一个包含 20 个从站的 hadoop 集群 每个从站都有 4 GB RAM 我将 Map 任务配置为 300MB 堆 Reduce 任务槽为 1GB 我每个节点有 2 个映射槽和 1
  • 与文件名中的冒号“:”作斗争

    我有以下代码 用于加载大量 csv gz 并将它们转储到其他文件夹中 并将源文件名作为一列 object DailyMerger extends App def allFiles path File List File val parts
  • 如何对 RDD 进行分区

    我有一个文本文件 其中包含大量由空格分隔的随机浮动值 我正在将此文件加载到 scala 中的 RDD 中 这个RDD是如何分区的 另外 是否有任何方法可以生成自定义分区 以便所有分区都具有相同数量的元素以及每个分区的索引 val dRDD
  • sqoop 通过 oozie 导出失败

    我正在尝试将数据导出到mysql from hdfs通过sqoop 我可以通过 shell 运行 sqoop 并且它工作正常 但是当我通过调用oozie 它出现以下错误并失败 我还包括了罐子 没有描述性日志 sqoop脚本 export c
  • 如何用snappy解压hadoop的reduce输出文件尾?

    我们的 hadoop 集群使用 snappy 作为默认编解码器 Hadoop作业减少输出文件名就像part r 00000 snappy JSnappy 无法解压缩文件 bcz JSnappy 需要以 SNZ 开头的文件 归约输出文件以某种
  • 是否可以通过编写单独的mapreduce程序并行执行Hive查询?

    我问了一些关于提高 Hive 查询性能的问题 一些答案与映射器和减速器的数量有关 我尝试使用多个映射器和减速器 但在执行中没有看到任何差异 不知道为什么 可能是我没有以正确的方式做 或者我错过了其他东西 我想知道是否可以并行执行 Hive
  • hive 中的授予权限在 hdp2.2 上不起作用

    我正在 CentOS 6 5 上使用 Ambari 设置来试验 HDP2 2 集群 但在运行 Hive GRANT 查询时遇到问题 例如 一个查询 grant select on Tbl1 to user root 给了我一个看起来像这样的
  • Protobuf RPC 在 Hadoop 2.2.0 单节点服务器上不可用?

    我正在尝试在按照本教程安装的本地单节点集群上运行 hadoop 2 2 0 mapreduce 作业 http codesfusion blogspot co at 2013 10 setup hadoop 2x 220 on ubuntu
  • Hadoop 超立方体

    嘿 我正在启动一个基于 hadoop 的超立方体 具有灵活的维度数 有人知道这方面现有的方法吗 我刚刚发现PigOLAP草图 http wiki apache org pig PigOLAPSketch 但没有代码可以使用它 另一种方法是Z

随机推荐