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个多小时
可以优化此查询吗?如果是,那么在哪里可以进行优化?
答案 0 :(得分:1)
我将尝试为您提供一些建议,以改善Hive
中的查询性能。
set hive.execution.engine;
如果执行引擎是mr而不是MapReduce
,则可以使用Apache Spark
或Apache Tez
,它们都比MapReduce
快。
set hive.execution.engine=tez;
可以用来解决此问题的一种策略是预先连接数据,并将预先连接的结果存储在单独的表中,然后可以查询该表。 这是非规范化规范化数据库的一种方法,以使运行分析查询更加容易。 这种预联接表的方法会产生一定的成本,但可以使分析查询更易于编写和运行。
还有其他一些技术可以提高Hive
查询性能
与任何类型的调整一样,了解系统的内部工作非常重要。当Hive执行联接时, 它需要选择要流传输的表和要缓存的表。 Hive将JOIN语句中的最后一个表用于流式传输,因此我们需要确保该流式传输表在两个表中最大。
A:1百万B:70万
因此,当将这两个表连接在一起时,重要的一点是较大的表在查询中排在最后。
它以有效的随机方式对数据进行划分,而不是像分区那样以可预测的方式进行划分。 将记录插入存储桶表中时,Hive将计算指定存储桶列中值的哈希码,并使用这些哈希码将记录划分为存储桶。 因此,存储有时会称为哈希分区。 存储的目标是在预定数量的存储桶中平均分配记录。 如果所有联接表都存储在联接键列上,则存储桶可以提高联接的性能。
有关存储桶的更多信息,请参见Hive
语言手册中描述存储桶表的页面,
分区
配置单元中的每个表都可以具有一个或多个分区键以标识特定分区。 使用分区,可以轻松地对数据切片进行查询。
答案 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分析函数(可能需要子查询,但也会节省内存)