NO1 基本描述
默认情况下,表的所有数据文件位于单个目录中。 分区是一种基于一个或多个列的值在加载期间物理划分数据以加快测试这些列的查询的技术。 例如,对于在年份列上分区的school_records表,对于每个不同的年值具有单独的数据目录,并且该年的所有数据存储在该目录中的数据文件中。 包括WHERE条件(例如YEAR = 1966,YEAR IN(1989,1999)或YEAR BETWEEN 1984 AND 1989)的查询可以仅检查来自适当目录或目录的数据文件,大大减少了要读取和测试的数据量 。
NO2 目录
一、何时使用分区表
四、刷新单个分区
五、分区子目录的权限
六、查询的分区修剪
七、分区键列
九、管理分区
NO3 内容
一、何时使用分区表
分区通常适用于:
1、非常大的表,其中读取整个数据集需要非常大的时间量。
2、始终或几乎总是查询分区列条件的表。
(1)在以年份分区的表的示例中,SELECT COUNT(*)FROM school_records WHERE year = 1985是有效的,只检查一小部分数据;
(2)SELECT COUNT(*)FROM school_records必须每年处理一个单独的数据文件,导致比未分区的表要多许多的总体工作。
注意:如果经常在不测试年份的情况下基于姓氏,学生ID等查询表格,则可能不会按此方式进行分区。
3、具有合理基数(不同值的数量)的列。
(1)如果列只有少量的值,例如男性或女性,则通过仅为每个查询删除大约50%的数据读取,效率并不高。
(2)如果列只有几个与每个值匹配的行,则要处理的目录数可能成为限制因素,每个目录中的数据文件可能太小,无法利用Hadoop机制在多兆字节块中传输数据 。
例如,您可以按年份分区人口普查数据,按年份和月份存储销售数据,按年份,月份和日期显示网络流量数据。
(具有大量传入数据的某些用户甚至可能分割到单独的小时和分钟。)
4、已通过提取,转换和加载(ETL)管道的数据。 分区列的值从原始数据文件中删除并由目录名称表示,因此将数据加载到分区表中涉及某种转换或预处理。
就Impala SQL语法而言,分区会影响以下语句:
1、CREATE TABLE:在创建表时标识PARTITIONED BY子句以标识分区列的名称和数据类型。 这些列不包括在表的主列表中。
备注:
(1)在CDH 5.7 / Impala 2.5及更高版本中,还可以在CREATE TABLE AS SELECT语句中使用PARTITIONED BY子句。
(2)此语法允许您使用单个语句创建分区表,将数据复制到其中,并基于插入数据中的值创建新分区
2、ALTER TABLE:您可以添加或删除分区,以处理巨大数据集的不同部分。 您可以指定用于保存特定分区的数据文件的HDFS目录。
使用按日期值分区的数据,您可能会“淘汰”不再相关的数据。
备注:
如果您是第一次创建分区并指定其位置,为获得最高效率,请使用包含ADD PARTITION和LOCATION子句的单个ALTER TABLE语句,
而不是使用ADD PARTITION和SET LOCATION子句的单独语句。
3、INSERT:将数据插入分区表时,可以标识分区列。 来自每个插入行的一个或多个值不存储在数据文件中,而是确定存储该行值的目录。
您还可以使用INSERT OVERWRITE语句指定将一组数据加载到哪个分区; 您可以替换特定分区的内容,但不能将数据追加到特定分区。
备注1:
默认情况下,如果INSERT语句在分区表下创建任何新的子目录,则为这些子目录分配impala用户的默认HDFS权限。
要使每个子目录与HDFS中的父目录具有相同的权限,请为impalad守护程序指定--insert_inherit_permissions启动选项。
备注2:
虽然无论表是否被分区,SELECT语句的语法都是相同的,但查询与分区表交互的方式可能对性能和可伸缩性产生显着影响。
在查询期间允许查询跳过某些分区的机制称为分区修剪; 有关详细信息,请参阅查询的分区修剪。
在Impala 1.4和更高版本中,有一个SHOW PARTITIONS语句可显示有关表中每个分区的信息。 有关详细信息,请参阅SHOW语句。
1、在SQL语句中指定所有分区列称为静态分区,因为语句会影响单个可预测分区。
例如,您使用具有影响仅一个分区的ALTER TABLE语句的静态分区,或使用将所有值插入同一分区的INSERT语句:
insert into t1 partition(x=10, y='a') select c1 from some_other_table;
2、在INSERT语句中指定某些分区键列,但忽略这些值时,Impala确定要插入哪个分区。 这种技术称为动态分区:
insert into t1 partition(x, y='b') select c1, c2 from some_other_table;
-- Create new partition if necessary based on variable year, month, and day; insert a single value.
insert into weather partition (year, month, day) select 'cloudy',2014,4,21;
-- Create new partition if necessary for specified year and month but variable day; insert a single value.
insert into weather partition (year=2014, month=04, day) select 'sunny',22;
备注:在PARTITION子句中指定的键列越多,SELECT列表中需要的列越少。 SELECT列表中的尾列将替换为没有指定值的分区键列。
四、刷新单个分区
1、当新数据文件通过某些非Impala机制(如Hive或Spark作业)加载到分区时,REFRESH语句通常用于分区表。
2、REFRESH语句使Impala了解新的数据文件,以便可以在Impala查询中使用它们。
3、由于分区表通常包含大量数据,因此完全分区表的REFRESH操作可能需要大量时间。
备注:
在CDH 5.9 / Impala 2.7及更高版本中,可以在REFRESH语句中包含PARTITION(partition_spec)子句,以便只刷新单个分区。
例如,REFRESH big_table PARTITION(year = 2017,month = 9,day = 30)。 分区规范必须包括所有分区键列。
有关REFRESH语法和用法的更多详细信息和示例,请参见REFRESH语句。
五、分区子目录的权限
1、默认情况下,如果INSERT语句在分区表下创建任何新的子目录,则为这些子目录分配impala用户的默认HDFS权限。
2、要使每个子目录具有与HDFS中的父目录相同的权限,请为impalad守护程序指定--insert_inherit_permissions启动选项。
六、查询的分区修剪
1、分区修剪是指查询可以跳过读取与一个或多个分区对应的数据文件的机制。
2、如果可以安排查询从查询执行计划中删除大量不必要的分区,则查询使用较少的资源,因此成比例更快,更具可扩展性。
例如:如果表按YEAR,MONTH和DAY列分区,则WHERE子句(如WHERE year = 2013,WHERE年<2010或WHERE年BETWEEN 1995 AND 1998)
允许Impala跳过所有分区外的数据文件 指定范围。 同样,WHERE年= 2013,AND月BETWEEN 1和3可以修剪更多的分区,只读取一年的一部分的数据文件。
3、继续阅读:
(1)检查分区修剪是否发生查询
a 要检查查询的分区修剪的有效性,请在运行查询之前检查EXPLAIN输出。
例如:此示例显示具有3个分区的表,其中查询只读取其中的1个。 EXPLAIN计划中的符号#partitions = 1/3确认Impala可以进行适当的分区修剪
[localhost:21000] > insert into census partition (year=2010) values ('Smith'),('Jones');
[localhost:21000] > insert into census partition (year=2011) values ('Smith'),('Jones'),('Doe');
[localhost:21000] > insert into census partition (year=2012) values ('Smith'),('Doe');
[localhost:21000] > select name from census where year=2010;
+-------+
| name |
+-------+
| Smith |
| Jones |
+-------+
[localhost:21000] > explain select name from census where year=2010;
+------------------------------------------------------------------+
| Explain String |
+------------------------------------------------------------------+
| PLAN FRAGMENT 0 |
| PARTITION: UNPARTITIONED |
| |
| 1:EXCHANGE |
| |
| PLAN FRAGMENT 1 |
| PARTITION: RANDOM |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 1 |
| UNPARTITIONED |
| |
| 0:SCAN HDFS |
| table=predicate_propagation.census #partitions=1/3 size=12B |
+------------------------------------------------------------------+
b 对于在查询的每个阶段实际读取和处理的数据量的报告,请在运行查询后立即检查SUMMARY命令的输出。
c 有关更详细的分析,请查看PROFILE命令的输出; 它在概要文件输出开始处附近包括此相同的摘要报告。
(2)什么SQL构造使用分区修剪
a Impala甚至可以通过将传递属性应用于WHERE子句的其他部分,在分区键列与常量不直接比较的情况下进行分区修剪。
b 此技术称为谓词传播,在Impala 1.2.2和更高版本中可用。 在此示例中,人口普查表包括指示何时收集数据的另一列,其以10年为间隔发生。
c 即使查询未将分区键列(YEAR)与常量值进行比较,Impala也可以推断只需要分区YEAR = 2010,并且再次只读取3个分区中的1个。
[localhost:21000] > drop table census;
[localhost:21000] > create table census (name string, census_year int) partitioned by (year int);
[localhost:21000] > insert into census partition (year=2010) values ('Smith',2010),('Jones',2010);
[localhost:21000] > insert into census partition (year=2011) values ('Smith',2020),('Jones',2020),('Doe',2020);
[localhost:21000] > insert into census partition (year=2012) values ('Smith',2020),('Doe',2020);
[localhost:21000] > select name from census where year = census_year and census_year=2010;
+-------+
| name |
+-------+
| Smith |
| Jones |
+-------+
[localhost:21000] > explain select name from census where year = census_year and census_year=2010;
+------------------------------------------------------------------+
| Explain String |
+------------------------------------------------------------------+
| PLAN FRAGMENT 0 |
| PARTITION: UNPARTITIONED |
| |
| 1:EXCHANGE |
| |
| PLAN FRAGMENT 1 |
| PARTITION: RANDOM |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 1 |
| UNPARTITIONED |
| |
| 0:SCAN HDFS |
| table=predicate_propagation.census #partitions=1/3 size=22B |
| predicates: census_year = 2010, year = census_year |
+------------------------------------------------------------------+
d 如果视图应用于分区表,则任何分区修剪都会考虑原始查询和查询中引用该视图的任何其他WHERE谓词的子句。
在Impala 1.4之前,只有来自CREATE VIEW语句的原始查询的WHERE子句用于分区修剪。
e 在涉及分析函数和分区表的查询中,分区修剪仅发生在分析函数调用的PARTITION BY子句中指定的列。
例如:如果分析函数查询具有WHERE year = 2016这样的子句,则使查询修剪所有其他YEAR分区的方法是在分析函数调用中包含PARTITION BY年;
例如:OVER(PARTITION BY年,other_columns other_analytic_clauses)。
(3)动态分区修剪
a 原始机制用于修剪分区是静态分区修剪,其中分析WHERE子句中的条件以提前确定哪些分区可以安全地跳过。
b 在Impala 2.5 / CDH 5.7及更高版本中,Impala可以执行动态分区修剪,其中在查询期间收集有关分区的信息,Impala以不可能提前预测的方式修剪不必要的分区。
c 例如:如果将分区键列与WHERE子句中的文字值进行比较,则Impala可以在计划阶段执行静态分区修剪,以便只读取相关分区:
-- The query only needs to read 3 partitions whose key values are known ahead of time.
-- That's static partition pruning.
SELECT COUNT(*) FROM sales_table WHERE year IN (2005, 2010, 2015);
d 动态分区修剪涉及使用仅在运行时可用的信息,例如子查询的结果:
create table yy (s string) partitioned by (year int) stored as parquet;
insert into yy partition (year) values ('1999', 1999), ('2000', 2000),
('2001', 2001), ('2010',2010);
compute stats yy;
create table yy2 (s string) partitioned by (year int) stored as parquet;
insert into yy2 partition (year) values ('1999', 1999), ('2000', 2000),
('2001', 2001);
compute stats yy2;
-- The query reads an unknown number of partitions, whose key values are only
-- known at run time. The 'runtime filters' lines show how the information about
-- the partitions is calculated in query fragment 02, and then used in query
-- fragment 00 to decide which partitions to skip.
explain select s from yy2 where year in (select year from yy where year between 2000 and 2005);
+----------------------------------------------------------+
| Explain String |
+----------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=16.00MB VCores=2 |
| |
| 04:EXCHANGE [UNPARTITIONED] |
| | |
| 02:HASH JOIN [LEFT SEMI JOIN, BROADCAST] |
| | hash predicates: year = year |
| | runtime filters: RF000 <- year |
| | |
| |--03:EXCHANGE [BROADCAST] |
| | | |
| | 01:SCAN HDFS [dpp.yy] |
| | partitions=2/4 files=2 size=468B |
| | |
| 00:SCAN HDFS [dpp.yy2] |
| partitions=2/3 files=2 size=468B |
| runtime filters: RF000 -> year |
+----------------------------------------------------------+
e 在这种情况下,Impala评估子查询,将子查询结果发送到参与查询的所有Impala节点,
然后每个impalad守护程序使用动态分区修剪优化来仅读取具有相关键值的分区
f 动态分区修剪对涉及多个大分区表的连接的查询特别有效。 评估连接谓词的ON子句通常可能需要从某些表的所有分区读取数据。
如果查询的WHERE子句引用分区键列,Impala现在通常可以在评估ON子句时跳过读取许多分区。
动态分区修剪优化减少了在查询期间通过网络存储和传输的I / O量和中间数据量。
g 当为查询中的连接节点激活溢出到磁盘功能时,Impala不会为该主机上的连接操作生成任何运行时过滤器。 查询中的其他连接节点不受影响。
h 动态分区修剪是运行时过滤功能的一部分,除了对分区表执行查询外,还应用于其他类型的查询。 有关此功能的完整详细信息,请参阅Impala查询的运行时过滤
七、分区键列
选择作为分区键的列应该是经常用于在重要的大规模查询中过滤查询结果的列。
典型的示例是数据具有相关联的时间值的年,月和日的某种组合,以及当数据与某个地方相关联时的地理区域。
1、对于基于时间的数据,将单独的部分拆分为其自己的列,因为Impala不能基于TIMESTAMP(时间戳)列进行分区。
2、分区列的数据类型对所需的存储没有显着影响,因为来自这些列的值不存储在数据文件中,而是表示为HDFS目录名称中的字符串。
3、在CDH 5.7 / Impala 2.5及更高版本中,可以启用OPTIMIZE_PARTITION_KEY_SCANS查询选项以加快只引用分区键列的查询,例如SELECT MAX(year)。
(1)默认情况下不启用此设置,因为如果表中包含没有实际数据的分区目录,查询行为会稍有不同。
(2)有关详细信息,请参阅OPTIMIZE_PARTITION_KEY_SCANS查询选项(仅限CDH 5.7或更高版本)。
4、分区表可以包含复杂类型列。 所有分区键列必须是标量类型。
5、请记住,当Impala查询存储在HDFS中的数据时,使用多兆字节文件利用HDFS块大小是最有效的。
对于Parquet表,Impala 2.0及更高版本中的块大小(以及数据文件的理想大小)为256 MB。
因此,避免指定太多的分区键列,这可能导致单个分区仅包含少量数据。 例如:
(1)如果您每天接收1 GB的数据,则可以按年,月和日划分; 而如果您每分钟接收5 GB的数据,则可以按年,月,日,小时和分钟进行分区。
(2)如果您具有地理组件的数据,则如果每个邮政编码有多个兆字节的数据,则可以根据邮政编码进行分区,但如果没有,
则可以按一些较大的区域进行分区,例如城市,州或国家/地区
备注:
如果经常在分区键列上运行聚合函数(如MIN(),MAX()和COUNT(DISTINCT)),请考虑启用OPTIMIZE_PARTITION_KEY_SCANS查询选项,
以优化此类查询。 此功能在CDH 5.7 / Impala 2.5及更高版本中提供。
对于此选项适用的查询种类,请参阅OPTIMIZE_PARTITION_KEY_SCANS查询选项(仅限CDH 5.7或更高版本),以及启用此查询选项时如何评估分区的细微差异。
1、分区表可以灵活地为不同分区使用不同的文件格式。 (有关Impala支持的不同文件格式的背景信息,请参阅Impala如何使用Hadoop文件格式。)
例如,如果最初以文本格式接收数据,然后以RCFile格式接收新数据,并最终开始接收Parquet格式的数据 ,所有数据可以驻留在同一个查询表中。
2、您只需要确保表的结构,使使用不同文件格式的数据文件驻留在单独的分区。
例如,下面是当您接收不同年份的数据时,如何从文本切换到Parquet数据:
[localhost:21000] > create table census (name string) partitioned by (year smallint);
[localhost:21000] > alter table census add partition (year=2012); -- Text format;
[localhost:21000] > alter table census add partition (year=2013); -- Text format switches to Parquet before data loaded;
[localhost:21000] > alter table census partition (year=2013) set fileformat parquet;
[localhost:21000] > insert into census partition (year=2012) values ('Smith'),('Jones'),('Lee'),('Singh');
[localhost:21000] > insert into census partition (year=2013) values ('Flores'),('Bogomolov'),('Cooper'),('Appiah');
3、此时,year = 2012的HDFS目录包含文本格式的数据文件,而year = 2013的HDFS目录包含Parquet数据文件。
与以往一样,加载非平凡数据时,您可以使用:
INSERT ... SELECT或LOAD DATA以大批量导入数据,而不是INSERT ... VALUES,它会生成对现实世界查询无效的小文件。
4、对于Impala无法本地创建的其他文件类型,可以切换到Hive并在那里发出ALTER TABLE ... SET FILEFORMAT语句和INSERT或LOAD DATA语句。
切换回Impala后,发出REFRESH table_name语句,以便Impala可以识别通过Hive添加的任何分区或新数据
九、管理分区
您可以添加,删除,设置预期的文件格式,或者为Impala表中的各个分区设置数据文件的HDFS位置。
有关语法详细信息和为分区设置不同的文件格式,请参阅ALTER TABLE语句有关管理包含具有不同文件格式的分区的表的提示。
提示:
如果您是第一次创建分区并指定其位置,为获得最高效率,请使用包含ADD PARTITION和LOCATION子句的单个ALTER TABLE语句,
而不是使用ADD PARTITION和SET LOCATION子句的单独语句。
备注:
(1)删除分区时对数据文件的影响取决于分区表是指定为内部还是外部。 对于内部(受管)表,将删除数据文件。
(2)例如,如果分区表中的数据是存储在其他位置的原始数据文件的副本,则可以通过删除报告不再需要的旧分区来节省磁盘空间,
因为知道原始数据仍然可用(如果需要)。
(3)对于外部表,数据文件保留。 例如,删除分区而不删除关联文件,Impala会考虑使用较小的分区集,从而提高查询效率并减少对表的DDL操作的开销;
(4)如果以后再次需要数据,您可以再次添加分区。 有关详细信息和示例,请参阅Impala表概述