我遇到了需要转换为redshift/mysql等效的配置单元表。我在理解配置单元查询结构时遇到问题,希望您能提供帮助:
CREATE TABLE IF NOT EXISTS table_1 (
id BIGINT,
price DOUBLE,
asset string
)
PARTITIONED BY (
pt STRING
);
ALTER TABLE table_1 DROP IF EXISTS PARTITION (pt== '${yyyymmdd}');
INSERT OVERWRITE TABLE table_1 PARTITION (pt= '${yyyymmdd}')
select aa.id,aa.price,aa.symbol from
...
...
from
table_2 table
我很难理解partitioned by子句。如果我理解正确的话,这与mysql表分区不同,是一个特定于配置单元的动态分区。分区不定义列或键,而是按当前日期进行分区。
这是否意味着表1是按日期划分的?每天都有一个单独的分区?
随后在代码中有类似于
inner join table_new table on table.pt = '${yyyymmdd}' and ...
在这种情况下,它是否意味着只插入行 yyyymmdd
是否选择加入?
谢谢您。
2条答案
按热度按时间pxy2qtax1#
配置单元中的分区默认是hdfs中名为
key=value
+配置单元元存储中的元数据。您可以更改分区位置并在任何文件夹的顶部创建分区。这个
PARTITIONED BY (pt STRING)
定义类型为string而不是date的分区列pt。分区值存储在元数据中。pt列不在表数据文件中,它只在partitioned by中定义,所有分区值都存储在元数据中。如果动态加载分区,将创建名为pt='value'的分区文件夹。这句话动态创建分区:
这句话加载了一个静态分区:
未选择分区列,分区值在
hive --hivevar yyyymmdd=20200604 -f myscript.sql
i7uaboj42#
我将尝试在一个镜头解释什么是划分在Hive。首先是
何时使用表分区
表分区在以下情况下是好的:
读取整个数据集花费的时间太长
查询几乎总是按分区列过滤
分区列有合理数量的不同值
etl进程的数据生成按文件名或目录名拆分数据
分区列值不在数据本身中
不要对具有许多唯一值的列进行分区
示例:按名字划分客户
创建分区表
要创建分区表,请在create table语句中使用PARTITED by子句。分区列的名称和类型必须在partitioned by子句中指定,并且只能在partitioned by子句中指定。它们不能同时出现在所有其他列的列表中。
上面所示的create table语句示例创建表customers\u by\u country,该表由名为country的字符串列进行分区。注意,country列只出现在partitioned by子句中,而不出现在它上面的列列表中。本例仅指定一个分区列,但可以通过在partitioned by子句中使用逗号分隔的列列表来指定多个分区列。除了这些特定的区别之外,这个CREATETABLE语句与用于创建等效的非分区表的语句是相同的。
表分区的实现方式对于使用配置单元发出查询的用户来说是最透明的。分区列称为虚拟列,因为它的值不存储在数据文件中。以下是测试结果
DESCRIBE
国家对客户的指挥;它显示分区列country,就像它是表中的普通列一样。您可以在select语句的任何常用子句中引用分区列。可以动态或静态地加载分区表中的数据
使用动态分区加载数据
将数据加载到分区表的一种方法是使用动态分区,它在加载数据时使用分区列中的值自动定义分区(另一种方法是使用静态分区手动定义分区)
要使用动态分区,必须使用insert语句加载数据。在insert语句中,必须使用partition子句列出分区列。要插入的数据必须包含分区列的值。分区列必须是要插入的数据中最右边的列,并且它们的顺序必须与在partition子句中出现的顺序相同。
上面所示的示例使用insert…select语句将数据加载到带有动态分区的customers\u by\u country表中。注意,分区列country包含在partition子句中,并在select列表中最后指定。
当hive执行此语句时,它会自动为country列创建分区,并根据country列中的值将数据加载到这些分区中。分区子目录中的结果数据文件不包括country列的值。由于国家是基于数据文件所在的子目录而知道的,因此在数据文件中也包含国家值是多余的。
查看customers\u by\u country目录的内容。它现在应该为country列中的每个值都有一个子目录。
查看其中一个目录中的文件。请注意,该文件包含来自该国家/地区的客户的行,而不包含其他行;另请注意,未包含country值。
注意:hive包含一个安全特性,可以防止用户意外地创建或覆盖大量分区(请参阅“使用分区的风险”了解更多信息。)默认情况下,配置单元设置属性
hive.exec.dynamic.partition.mode
严格要求。这会阻止您使用动态分区,尽管您仍然可以使用静态分区。通过设置属性,可以在配置单元中禁用此安全功能
hive.exec.dynamic.partition.mode
非严格:然后可以使用insert语句动态加载数据。
在beeline中设置的配置单元属性仅适用于当前会话,因此下次启动配置单元会话时,此属性将被设置回strict。但如果需要,您或系统管理员可以永久配置属性。
在分区表上运行某些select查询时,如果表足够大,则可以注意到运行所需时间的显著差异。请注意,查询表与查询customers表没有任何区别。
使用静态分区加载数据
将数据加载到分区表的一种方法是使用静态分区,即手动定义不同的分区。
对于静态分区,您可以使用altertable…add partition语句手动创建分区,然后将数据加载到分区中。
例如,此alter table语句为巴基斯坦(pk)创建分区:
注意分区列名(country)和定义这个分区的特定值(pk)是如何在addpartition子句中指定的。这将在customers\u by\u country表目录中创建一个名为country=pk的分区目录。
为巴基斯坦创建分区后,可以使用insert…select语句将数据添加到分区中:
注意在partition子句中,如何指定分区列名(country)和特定值(pk),就像在用于创建分区的addpartition命令中一样。还要注意,在select语句中,分区列不包括在select列表中。最后,请注意select语句中的where子句只选择来自巴基斯坦的客户。
对于静态分区,您需要为每个分区重复这两个步骤:首先创建分区,然后添加数据。实际上,您可以使用任何方法来加载数据;不需要使用insert语句。您可以改为使用hdfs dfs命令或load data inpath命令。但是,无论您如何加载数据,您都有责任确保数据存储在正确的分区子目录中。例如,巴基斯坦客户的数据必须存储在巴基斯坦分区子目录中,其他国家客户的数据必须存储在这些国家的分区子目录中。
当加载到表中的数据已经基于分区列划分为文件时,或者当数据以与分区列一致的方式增长时,静态分区最有用:例如,假设您的公司在另一个国家(如新西兰(“nz”)开设了一个新商店,你得到了一份新客户的数据文件,都来自那个国家。您可以轻松地添加一个新分区并将该文件加载到其中。
使用分区的风险
使用分区时的一个主要风险是创建分区会导致小文件问题。当这种情况发生时,对表进行分区实际上会降低查询性能(与使用分区时的目标相反),因为它会导致创建太多的小文件。这在使用动态分区时更可能发生,但是静态分区仍然可能发生,例如,如果您每天向sales表添加一个新分区,其中包含前一天的销售额,并且每天的数据不是特别大。
在选择分区时,您希望在太多的分区(导致小文件问题)和太少的分区(提供的性能几乎没有好处)之间找到一个令人满意的平衡点。分区列应该有合理数量的分区值,但您认为合理的值很难量化。
使用动态分区尤其危险,因为如果不小心,很容易对具有太多不同值的列进行分区。想象一个用例,在这个用例中,您经常查找在查询中指定的时间范围内的数据。你可能会认为分开是个好主意