使用分区表进行查询优化

为了便于管理和提高性能,可以将Hive表拆分成更多的逻辑块。

Hive数据模型

在Hive中,数据库和表按照逻辑顺序排列为目录,便于操作和维护。即,Hive逻辑上将数据库和数据表存储为目录。

为什么要使用分区表?

默认情况下,Hive中的查询会扫描整个表来获取结果。

现在,考虑一个Hive表,它有数百万行。当一个简单的查询扫描该表时,它会消耗系统资源。而查询将花费大量时间来获取结果,这最终会影响hive应用程序的性能。

因此,在分析如此大的表时,我们需要一种技术来优化查询的性能,其中一种技术就是Hive中的Partitioning - 表分区。

分区表的意义在于优化查询。查询时尽量利用分区字段。如果不使用分区字段,就会全部扫描。

Hive中如何对表进行分区?

分区是Hive中的一种性能调优技术。它在Hive中使用一列或多列作为分区键在表中创建子目录。

例如,存储交易记录(或其它带有时间戳的数据集,如web日志)按日期分区,一天是一个分区。查询时候,我们可以查询某一天或一段时间的数据,只读取属性该时间的数据,Hive只扫描指定分区的数据分区表,以实现高效查询。

分区表实际就是对应HDFS文件系统上的的独立的文件夹,该文件是夹下是该分区所有数据文件。普通表和分区表的区别在于:一个Hive表在HDFS上是有一个对应的目录来存储数据,普通表的数据直接存储在这个目录下,而分区表数据存储时,是再划分子目录来存储的。一个分区一个子目录。主要作用是来优化查询性能。

例如:

如何创建分区表?

在下面的代码中,我们创建了名为emp的分区表,使用关键字partitioned by:

create table emp(
      name string, 
      age int
) partitioned by (provice string,city string);

在这里,用partitioned by指定创建的分区,多个分区意味着多级目录。在Hive中,可以使用多个列对表进行分区。注意,这里的provice字段和city字段并不在表结构中定义,它们属于表的隐式字段,用来创建对应的物理文件夹。

在Hive中,既可以分区托管表,也可以分区外部表。

插入的数据指定了不同的分区之后,会生成不同的文件夹。

hive> insert into emp partition(provice = "hebei", city = "baoding") values("tom",22);
hive> dfs -ls -R /user/hive/warehouse/;

往表中插入数据之后,会发现在表名对应的目录下,会多出两级目录。

/user/hive/warehouse/mydb.db/emp/provice=hebei
/user/hive/warehouse/mydb.db/emp/provice=hebei/city=baoding
/user/hive/warehouse/mydb.db/emp/provice=hebei/city=baoding/000000_0

如何加载数据到Hive分区表?

在Hive中有两种分区方式:

  • 1) 静态分区:在静态分区中,需要手工将数据插入到表的不同分区。
  • 2) 动态分区:在数据插入到表中时会自动进行分区存放。

例如,对于静态分区,批量load数据到不同的分区上:

hive>load data local inpath '/home/user1/emp.txt' overwrite into table t1 partition(provice = "hebei",city = "baoding");

hive>load data local inpath '/home/user1/emp.txt' overwrite into table t1 partition(provice = "hebei",city = "handan"); 

对于动态分区,可以在往表中插入数据的时候,动态的根据值来选择数据进入的分区。

hive>load data local inpath '/home/user1/emp.txt' overwrite into table t1 partition(provice,city);

hive>load data local inpath '/home/user1/emp.txt' overwrite into table t1 partition(provice,city);

动态分区默认是没有开启。可以通过执行以下命令开启动态分区。

hive> set hive.exec.dynamic.partition.mode=nonstrict       // 分区模式,默认strict		
hive> set hive.exec.dynamic.partition=true                 // 开启动态分区,默认false
hive> set hive.exec.max.dynamic.partitions=1000	           //最大动态分区数, 设为1000

Hive动态分区模式有两种:strice(严格模式)和nostrice(非严格模式)。

开启后默认是以严格模式执行的,在这种模式下需要至少一个分区字段是静态的。这有助于阻止因设计错误导致查询产生大量的分区。例如:用户可能错误使用时间戳作为分区表字段。然后导致每秒都对应一个分区!

我们可以关闭严格分区模式。

不管是静态分区还是动态分区,创建分区表的语法是一样的(区别在于插入数据时是否需要手工指定分区)。

查看表的分区信息

在插入两个分区的数据之后,查看表的分区信息,就会将这个表的所有分区都显示出来。

hive> show partitions mydb.table;

使用分区对数据进行过滤

分区表使用的分区字段不是在数据中存在的(比如创建了一个国家分区,但是数据中并没有这个字段),分区字段只是为了在HDFS上产生了对应的子目录。

在使用hive查询的时候,完全可以使用where对分区进行过滤。

hive> select * from t3 where city='changchun';

修改分区

修改分区意味着对原有的分区进行增减,即重构分区。

添加分区:不改变分区的级数,而是改变分区字段的值。

hive> alter table emp add partition(provice = "hebei", city = "shijiazhuang");

hive> show partitions emp;

分区对应的是HDFS上的目录,分区的删除涉及到对应的数据是否会被删除的问题。如果此表是内部表的话,那么分区的删除意味着对应目录下的数据会被删除;如果是外部表的话,分区的删除就不会删除对应的数据文件。

hive> alter table emp drop partition(provice = "hebei", city = "shijiazhuang");

hive> show partitions emp;

《Spark原理深入与编程实战》