配置单元联接查询优化

时间:2020-04-12 10:10:25

标签: optimization hive bigdata query-optimization hiveql

SELECT 
  A.col1,
  A.col2,
  B.Bdate bdate,
  SUM(qty)*COLLECT_LIST(cost)[0] price 
FROM A 
JOIN B 
ON (A.col2 = B.col2 AND A.Adate <= B.Bdate) 
GROUP BY 
  A.col1,
  A.col2,
  B.bdate;

表的大小如下:

A:100万 B:700k

考虑此查询:

/[\d()+-*/.]/g

上面的配置单元查询在4个从属(8GB内存,100 GB磁盘)和1个主服务器(16 GB内存,100 GB磁盘)的群集上花费了3个多小时

可以优化此查询吗?如果是,那么在哪里可以进行优化?

2 个答案:

答案 0 :(得分:1)

我将尝试为您提供一些建议,以改善Hive中的查询性能。

  • 检查您正在使用的执行引擎
set hive.execution.engine;

如果执行引擎是mr而不是MapReduce,则可以使用Apache SparkApache Tez,它们都比MapReduce快。

set hive.execution.engine=tez;
  • 联接查询的计算量很大并且运行速度很慢,尤其是当您联接三个或更多表时,或者正在处理非常大的数据时。

可以用来解决此问题的一种策略是预先连接数据,并将预先连接的结果存储在单独的表中,然后可以查询该表。 这是非规范化规范化数据库的一种方法,以使运行分析查询更加容易。 这种预联接表的方法会产生一定的成本,但可以使分析查询更易于编写和运行。

还有其他一些技术可以提高Hive查询性能

  • 联接表排序(最后一个表最大)

与任何类型的调整一样,了解系统的内部工作非常重要。当Hive执行联接时, 它需要选择要流传输的表和要缓存的表。 Hive将JOIN语句中的最后一个表用于流式传输,因此我们需要确保该流式传输表在两个表中最大。

A:1百万B:70万

因此,当将这两个表连接在一起时,重要的一点是较大的表在查询中排在最后。

  • 装桶将数据存储在单独的文件中,而不是诸如分区之类的单独子目录中。

它以有效的随机方式对数据进行划分,而不是像分区那样以可预测的方式进行划分。 将记录插入存储桶表中时,Hive将计算指定存储桶列中值的哈希码,并使用这些哈希码将记录划分为存储桶。 因此,存储有时会称为哈希分区。 存储的目标是在预定数量的存储桶中平均分配记录。 如果所有联接表都存储在联接键列上,则存储桶可以提高联接的性能。

有关存储桶的更多信息,请参见Hive语言手册中描述存储桶表的页面,

BucketedTables

bucketing-in-hive

分区

  • 分区是一种基于日期,城市和部门等特定列的值将表划分为相关部分的方法。

配置单元中的每个表都可以具有一个或多个分区键以标识特定分区。 使用分区,可以轻松地对数据切片进行查询。

apache-hive-partitions

答案 1 :(得分:1)

使用Tez和mapjoin。

set hive.auto.convert.join=true; --this enables map-join
set hive.mapjoin.smalltable.filesize=25000000; --adjust for your smaller table to fit in memory
set hive.execution.engine=tez;

此计算的存储效率也不高:

SUM(qty)*COLLECT_LIST(cost)[0] price 

COLLECT_LIST会将组中的所有成本值收集为非唯一的(包含组中所有行的值)和无序(是的,无序的,因为您没有在collect_list之前添加任何sort + sort)数组。该数组可能足够大(元素数=组中的行数),具体取决于您的数据,那么您采用的是[0]元素,这意味着您仅从组中选择任何随机成本。收集数组以获取任意随机元素有意义吗?请改用min()max。如果应该采用哪个cost无关紧要,则min(cost)max(cost)或其他标量函数将消耗更少的内存。您可以使用first_value分析函数(可能需要子查询,但也会节省内存)