Impala 分区表-2


与分区一起执行的SQL

通过将传递属性应用于WHERE子句的其他部分,Impala 甚至可以在分区键列不直接与常量进行比较的情况下进行分区修剪。这种技术称为谓词传播,可在 Impala 1.2.2 及更高版本中使用。在此示例中,人口普查表包含另一列,指示收集数据的时间,该时间间隔为 10 年。即使查询未将分区键列 ( 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          |
+------------------------------------------------------------------+

如果视图适用于分区表,则任何分区修剪都会考虑原始查询中的子句以及WHERE查询中引用该视图的任何附加谓词。在 Impala 1.4 之前,只有WHERE 语句中原始查询的子句CREATE VIEW用于分区修剪。

在涉及分析函数和分区表的查询中,分区修剪仅对PARTITION BY在分析函数调用的子句中命名的列发生。例如,如果一个解析函数查询有一个诸如 的子句 WHERE year=2016,则使查询修剪所有其他 YEAR分区的方法是包含PARTITION BY year在解析函数调用中;例如,。 OVER (PARTITION BY year,other_columns other_analytic_clauses)

动态分区修剪

原来用来修剪分区的机制是静态分区修剪,其中WHERE分析子句中的条件 来预先确定可以安全地跳过哪些分区。在Impala 2.5 及更高版本中,Impala 可以执行动态分区修剪,其中在查询期间收集有关分区的信息,并且 Impala 以无法提前预测的方式修剪不必要的分区。

例如,如果将分区键列与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);

动态分区修剪涉及使用仅在运行时可用的信息,例如子查询的结果。以下示例显示了一个简单的动态分区修剪。

CREATE TABLE yy (s STRING) PARTITIONED BY (year INT);
INSERT INTO yy PARTITION (year) VALUES ('1999', 1999), ('2000', 2000),
  ('2001', 2001), ('2010', 2010), ('2018', 2018);
COMPUTE STATS yy;

CREATE TABLE yy2 (s STRING, year INT);
INSERT INTO yy2 VALUES ('1999', 1999), ('2000', 2000), ('2001', 2001);
COMPUTE STATS yy2;

-- The following query reads an unknown number of partitions, whose key values
-- are only known at run time. The runtime filters line shows the
-- information used in query fragment 02 to decide which partitions to skip.

EXPLAIN SELECT s FROM yy WHERE year IN (SELECT year FROM yy2);
+--------------------------------------------------------------------------+
| PLAN-ROOT SINK                                                           |
| |                                                                        |
| 04:EXCHANGE [UNPARTITIONED]                                              |
| |                                                                        |
| 02:HASH JOIN [LEFT SEMI JOIN, BROADCAST]                                 |
| |  hash predicates: year = year                                          |
| |  runtime filters: RF000 <- year                                   |
| |                                                                        |
| |--03:EXCHANGE [BROADCAST]                                               |
| |  |                                                                     |
| |  01:SCAN HDFS [default.yy2]                                            |
| |     partitions=1/1 files=1 size=620B                                   |
| |                                                                        |
| 00:SCAN HDFS [default.yy]                                                |
|    partitions=5/5 files=5 size=1.71KB                               |
|    runtime filters: RF000 -> year                                        |
+--------------------------------------------------------------------------+

SELECT s FROM yy WHERE year IN (SELECT year FROM yy2); -- Returns 3 rows from yy
PROFILE;

在上面的例子中,Impala 评估子查询,将子查询结果发送到所有参与查询的 Impala 节点,然后每个impalad守护进程使用动态分区修剪优化来只读取具有相关键值的分区。

EXPLAIN语句的输出查询计划显示已启用运行时过滤器。该计划还显示它希望读取yy表的所有 5 个分区,表明不会发生静态分区修剪。

PROFILE输出中 的过滤器摘要显示扫描节点根据动态分区修剪的运行时过滤器过滤掉。

Filter 0 (1.00 MB):
 - Files processed: 3
 - Files rejected: 1 (1)
 - Files total: 3 (3)

动态分区修剪对于涉及多个大型分区表的连接的查询特别有效。评估ON连接谓词的 子句通常可能需要从某些表的所有分区读取数据。如果WHERE查询的子句引用分区键列,Impala 现在通常可以在评估ON子句时跳过读取许多分区。动态分区修剪优化减少了 I/O 量以及查询期间通过网络存储和传输的中间数据量。

当为查询中的连接节点激活溢出到磁盘功能时,Impala 不会为该主机上的连接操作生成任何运行时过滤器。查询中的其他连接节点不受影响。

动态分区修剪是运行时过滤功能的一部分,除了针对分区表的查询之外,它还适用于其他类型的查询。

分区键列

您选择作为分区键的列应该是在重要的大规模查询中经常用于过滤查询结果的列。流行的示例是数据与时间值相关联时的年、月和日的某种组合,以及数据与某个地方相关联时的地理区域。

  • 对于基于时间的数据,将单独的部分拆分为各自的列,因为 Impala 无法基于TIMESTAMP列进行分区 。
  • 分区列的数据类型对所需的存储没有显着影响,因为来自这些列的值不存储在数据文件中,而是在 HDFS 目录名称中表示为字符串。
  • 在Impala 2.5及更高版本中,您可以启用OPTIMIZE_PARTITION_KEY_SCANS查询选项来加速仅引用分区键列的查询,例如SELECT MAX(year). 默认情况下不启用此设置,因为如果表包含分区目录而内部没有实际数据,则查询行为会略有不同。
  • 分区表可以包含复杂类型的列。所有分区键列必须是标量类型。
  • 请记住,当 Impala 查询存储在 HDFS 中的数据时,使用多兆字节文件来利用 HDFS 块大小是最有效的。对于 Parquet 表,Impala 2.0 及更高版本中的块大小(和数据文件的理想大小)为256 MB. 因此,避免指定过多的分区键列,这可能导致单个分区仅包含少量数据。例如,如果您每天收到 1 GB 的数据,您可以按年、月和日进行分区;而如果您每分钟收到 5 GB 的数据,您可以按年、月、日、小时和分钟进行分区。如果您有包含地理成分的数据,并且每个邮政编码都有许多兆字节的数据,那么您可能会根据邮政编码进行分区,但如果没有,您可能会根据一些更大的区域(例如城市、州或国家/地区)进行分区。状态

如果你频繁地运行聚合函数,例如MIN(), MAX()COUNT(DISTINCT)上分区键列,考虑启用OPTIMIZE_PARTITION_KEY_SCANS查询选项,优化这样的查询。此功能在Impala 2.5 及更高版本中可用。

为分区设置不同的文件格式

分区表可以灵活地为不同的分区使用不同的文件格式。例如,如果您最初以文本格式接收数据,然后以 RCFile 格式接收新数据,最终开始以 Parquet 格式接收数据,所有这些数据都可以驻留在同一个表中进行查询。您只需要确保表结构化,以便使用不同文件格式的数据文件驻留在不同的分区中。

例如,当您接收不同年份的数据时,您可以通过以下方式从文本数据切换到 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');

此时,HDFS 目录中year=2012包含一个文本格式的数据文件,而 HDFS 目录中 year=2013包含一个 Parquet 数据文件。与往常一样,在加载重要数据时,您将使用INSERT ... SELECTLOAD DATA大批量导入数据,而不是INSERT ... VALUES生成对实际查询效率低下的小文件。

对于 Impala 无法在本地创建的其他文件类型,您可以切换到 Hive 并在那里发出ALTER TABLE ... SET FILEFORMAT语句和/INSERTLOAD DATA语句。切换回 Impala 后,发出一条语句,以便 Impala 识别通过 Hive 添加的任何分区或新数据。 REFRESH table_name

管理分区

您可以为 Impala 表中的各个分区添加、删除、设置预期的文件格式或设置数据文件的 HDFS 位置。

注意: 如果您是第一次创建分区并指定其位置,为了获得最大效率,请使用ALTER TABLE包含ADD PARTITIONandLOCATION子句的单个语句,而不是包含ADD PARTITIONandSET LOCATION子句的单独语句。

删除分区时数据文件会发生什么取决于分区表是指定为内部表还是外部表。对于内部(托管)表,数据文件被删除。例如,如果分区表中的数据是存储在其他地方的原始数据文件的副本,您可以通过删除不再需要报告的旧分区来节省磁盘空间,因为如果以后需要原始数据仍然可用。对于外部表,数据文件是单独保留的。例如,删除一个分区而不删除关联的文件,让 Impala 可以考虑更小的分区集,提高查询效率并减少对表进行 DDL 操作的开销;如果稍后再次需要数据,您可以再次添加分区。

对 Kudu 表使用分区

Kudu 表使用比包含 HDFS 数据文件的表更细粒度的分区方案。您PARTITION BY可以在CREATE TABLE语句中指定一个子句来标识如何从分区键列中划分值。

使分区表的统计信息保持最新

由于在COMPUTE STATS添加新分区时在分区表上运行该语句可能会占用大量资源,因此 Impala 包含此语句的一个变体,它允许在每个分区的基础上计算统计信息,以便在添加新分区时可以增量更新统计信息。

重要的:

对于特定的表,使用COMPUTE STATSCOMPUTE INCREMENTAL STATS,但不要将两者结合或交替使用。如果 在表的生命周期内从 切换COMPUTE STATSCOMPUTE INCREMENTAL STATS,反之亦然,请DROP STATS在切换之前运行以删除所有统计信息 。

当您第一次COMPUTE INCREMENTAL STATS在表上运行时,无论该表是否已有统计信息,都会从头开始重新计算统计信息。因此,当COMPUTE INCREMENTAL STATS第一次在给定表上运行时,期望一次扫描整个表的资源密集型操作。

在 Impala 3.0 及更低版本中,每个分区的每列大约需要 400 字节的元数据用于缓存。有一个大的分区数和多列的表可以添加到一个显著内存开销为元数据必须在上缓存 catalogd主机和每个上impalad主机有资格成为一个协调者。如果所有表的元数据超过 2 GB,您可能会遇到服务停机。在 Impala 3.1 及更高版本中,该问题通过改进对增量统计信息的处理得到缓解。

COMPUTE INCREMENTAL STATS变体仅计算自上一条COMPUTE INCREMENTAL STATS语句以来添加或更改的分区的统计信息,而不是整个表。它通常用于COMPUTE STATS 每次添加或删除分区时完整操作花费太长时间而不切实际的表。

-- Initially the table has no incremental stats, as indicated
-- 'false' under Incremental stats.
show table stats item_partitioned;
+-------------+-------+--------+----------+--------------+---------+------------------
| i_category  | #Rows | #Files | Size     | Bytes Cached | Format  | Incremental stats
+-------------+-------+--------+----------+--------------+---------+------------------
| Books       | -1    | 1      | 223.74KB | NOT CACHED   | PARQUET | false
| Children    | -1    | 1      | 230.05KB | NOT CACHED   | PARQUET | false
| Electronics | -1    | 1      | 232.67KB | NOT CACHED   | PARQUET | false
| Home        | -1    | 1      | 232.56KB | NOT CACHED   | PARQUET | false
| Jewelry     | -1    | 1      | 223.72KB | NOT CACHED   | PARQUET | false
| Men         | -1    | 1      | 231.25KB | NOT CACHED   | PARQUET | false
| Music       | -1    | 1      | 237.90KB | NOT CACHED   | PARQUET | false
| Shoes       | -1    | 1      | 234.90KB | NOT CACHED   | PARQUET | false
| Sports      | -1    | 1      | 227.97KB | NOT CACHED   | PARQUET | false
| Women       | -1    | 1      | 226.27KB | NOT CACHED   | PARQUET | false
| Total       | -1    | 10     | 2.25MB   | 0B           |         |
+-------------+-------+--------+----------+--------------+---------+------------------

-- After the first COMPUTE INCREMENTAL STATS,
-- all partitions have stats. The first
-- COMPUTE INCREMENTAL STATS scans the whole
-- table, discarding any previous stats from
-- a traditional COMPUTE STATS statement.
compute incremental stats item_partitioned;
+-------------------------------------------+
| summary                                   |
+-------------------------------------------+
| Updated 10 partition(s) and 21 column(s). |
+-------------------------------------------+
show table stats item_partitioned;
+-------------+-------+--------+----------+--------------+---------+------------------
| i_category  | #Rows | #Files | Size     | Bytes Cached | Format  | Incremental stats
+-------------+-------+--------+----------+--------------+---------+------------------
| Books       | 1733  | 1      | 223.74KB | NOT CACHED   | PARQUET | true
| Children    | 1786  | 1      | 230.05KB | NOT CACHED   | PARQUET | true
| Electronics | 1812  | 1      | 232.67KB | NOT CACHED   | PARQUET | true
| Home        | 1807  | 1      | 232.56KB | NOT CACHED   | PARQUET | true
| Jewelry     | 1740  | 1      | 223.72KB | NOT CACHED   | PARQUET | true
| Men         | 1811  | 1      | 231.25KB | NOT CACHED   | PARQUET | true
| Music       | 1860  | 1      | 237.90KB | NOT CACHED   | PARQUET | true
| Shoes       | 1835  | 1      | 234.90KB | NOT CACHED   | PARQUET | true
| Sports      | 1783  | 1      | 227.97KB | NOT CACHED   | PARQUET | true
| Women       | 1790  | 1      | 226.27KB | NOT CACHED   | PARQUET | true
| Total       | 17957 | 10     | 2.25MB   | 0B           |         |
+-------------+-------+--------+----------+--------------+---------+------------------

-- Add a new partition...
alter table item_partitioned add partition (i_category='Camping');
-- Add or replace files in HDFS outside of Impala,
-- rendering the stats for a partition obsolete.
!import_data_into_sports_partition.sh
refresh item_partitioned;
drop incremental stats item_partitioned partition (i_category='Sports');
-- Now some partitions have incremental stats
-- and some do not.
show table stats item_partitioned;
+-------------+-------+--------+----------+--------------+---------+------------------
| i_category  | #Rows | #Files | Size     | Bytes Cached | Format  | Incremental stats
+-------------+-------+--------+----------+--------------+---------+------------------
| Books       | 1733  | 1      | 223.74KB | NOT CACHED   | PARQUET | true
| Camping     | -1    | 1      | 408.02KB | NOT CACHED   | PARQUET | false
| Children    | 1786  | 1      | 230.05KB | NOT CACHED   | PARQUET | true
| Electronics | 1812  | 1      | 232.67KB | NOT CACHED   | PARQUET | true
| Home        | 1807  | 1      | 232.56KB | NOT CACHED   | PARQUET | true
| Jewelry     | 1740  | 1      | 223.72KB | NOT CACHED   | PARQUET | true
| Men         | 1811  | 1      | 231.25KB | NOT CACHED   | PARQUET | true
| Music       | 1860  | 1      | 237.90KB | NOT CACHED   | PARQUET | true
| Shoes       | 1835  | 1      | 234.90KB | NOT CACHED   | PARQUET | true
| Sports      | -1    | 1      | 227.97KB | NOT CACHED   | PARQUET | false
| Women       | 1790  | 1      | 226.27KB | NOT CACHED   | PARQUET | true
| Total       | 17957 | 11     | 2.65MB   | 0B           |         |
+-------------+-------+--------+----------+--------------+---------+------------------

-- After another COMPUTE INCREMENTAL STATS,
-- all partitions have incremental stats, and only the 2
-- partitions without incremental stats were scanned.
compute incremental stats item_partitioned;
+------------------------------------------+
| summary                                  |
+------------------------------------------+
| Updated 2 partition(s) and 21 column(s). |
+------------------------------------------+
show table stats item_partitioned;
+-------------+-------+--------+----------+--------------+---------+------------------
| i_category  | #Rows | #Files | Size     | Bytes Cached | Format  | Incremental stats
+-------------+-------+--------+----------+--------------+---------+------------------
| Books       | 1733  | 1      | 223.74KB | NOT CACHED   | PARQUET | true
| Camping     | 5328  | 1      | 408.02KB | NOT CACHED   | PARQUET | true
| Children    | 1786  | 1      | 230.05KB | NOT CACHED   | PARQUET | true
| Electronics | 1812  | 1      | 232.67KB | NOT CACHED   | PARQUET | true
| Home        | 1807  | 1      | 232.56KB | NOT CACHED   | PARQUET | true
| Jewelry     | 1740  | 1      | 223.72KB | NOT CACHED   | PARQUET | true
| Men         | 1811  | 1      | 231.25KB | NOT CACHED   | PARQUET | true
| Music       | 1860  | 1      | 237.90KB | NOT CACHED   | PARQUET | true
| Shoes       | 1835  | 1      | 234.90KB | NOT CACHED   | PARQUET | true
| Sports      | 1783  | 1      | 227.97KB | NOT CACHED   | PARQUET | true
| Women       | 1790  | 1      | 226.27KB | NOT CACHED   | PARQUET | true
| Total       | 17957 | 11     | 2.65MB   | 0B           |         |
+-------------+-------+--------+----------+--------------+---------+------------------