Hive之Table、External Table、Partition、Bucket区别

服务器

  - Hive 是一个建立在hadoop文件系统上的数据仓库架构,可以用其对hdfs上数据进行分析

  - 实际上是将hdfs上的文件映射成table(按文件格式创建table,然后hive的数据仓库会生成对应的目录,默认的仓库路径:user/hive/warehouse/tablename,目录名与这个表名相同,这时只要将符合table定义的文件加载到该目录便可通过Hql对整个目录的文件进行查询了。

  - 将数据加载到该目录可以用hdfs dfs -put 命令直接添加到该目录;

  - 也可以通过load data local inpath ‘user/test.txt’ into table tableName,通过load命令加载数据与通过put命令加载文件的结果是一样的,即在user/hive/warehouse/tablename 目录下都会有加载进来的文件,如果用load命令加载的是hdfs上的文件则会将原hdfs目录下对应的文件移动至hive的仓库目录下),并将这些元数据保存到关系型数据库中,元数据存储着表所对应的文件路径,表的列与分区,表创建时间,文件大小等属性;

  - 同时用户运用类sql对文件进行操作,这个操作主要是查询。

  - hive 的数据模型中四种表:

  ```

   -Table内部表

   -External Table 外部表

   -Partition分区表

   -Bucket Table 桶表

  ```

  - 内部表

  ```

  1. 表:Hive中的表和关系型数据库中的表在概念上很类似,每个表在HDFS中都有相应的目录用来存储表的数据,这个目录可以通过${HIVE_HOME}/conf/hive-site.xml配置文件中的hive.metastore.warehouse.dir属性来配置,这个属性默认的值是/user/hive/warehouse(这个目录在HDFS上),我们可以根据实际的情况来修改这个配置。

  2. 如果我有一个表test,那么在HDFS中会创建/user/hive/warehouse/test目录(这里假定hive.metastore.warehouse.dir配置为/user/hive/warehouse);test表所对应的所有数据都存放在这个目录中。

  3. 如果删除这张表,则表在关系数据中存储的元数据以及在warehouse目录下的数据也会被清除掉。

  ```

  - External Table 外部表

  ```

  Hive中的外部表和表很类似,但是其数据不是放在自己表所属的目录中,而是存放到别处,这样的好处是如果你要删除这个外部表,该外部表所指向的数据是不会被删除的,它只会删除外部表对应的元数据;而如果你要删除内部表,该表对应的所有数据包括元数据都会被删除。

  ```

  ###### 外部表操作演示

  - 创建外部表(创建的时候得用LOCATION 指定原数据存储的路径,不指定的话hive会在user/hive/warehouse下以外部表的表名创建目录并将数据存储在这里)

  ```

  create EXTERNAL table t_external (year string,month int,num int)

  ROW FORMAT DELIMITED

  FIELDS TERMINATED BY ,

  LOCATION /usr/exts;

  ```

  - 加载数据可用:hdfs dfs -put filename /usr/exts

  也可用: hive>load data local inpath ‘/home/centosm/test/hive’ into table t_external;

  执行load 命令之前数据如下所示:

  hadoop fs -ls /usr/exts

  - 查询外部表中的文件路径

  ```

  select INPUT__FILE__NAME from t_external;

  ```

  - 如果删除外部表,只会将其对应的元数据删除了,目录中的数据并不会被删除

  ```

  hive> drop table t_external;

  hive> select * from t_external;

  FAILED: SemanticException [Error 10001]: Line 1:14 Table not found t_external

  ```

  由上可见对应的数据并没有被删除。

  综上所述:外部表与内部表的区别如下

  1、在导入数据到外部表,数据并没有移动到自己的数据仓库目录下,也就是说外部表中的数据并不是由它自己来管理的!而表则不一样;

  2、在删除表的时候,Hive将会把属于表的元数据和数据全部删掉;而删除外部表的时候,Hive仅仅删除外部表的元数据,数据是不会删除的!

  那么,应该如何选择使用哪种表呢?在大多数情况没有太多的区别,因此选择只是个人喜好的问题。但是作为一个经验,如果所有处理都需要由Hive完成,那么你应该创建表,否则使用外部表!

  - 分区表

  在Hive中,表的每一个分区对应表下的相应目录,所有分区的数据都是存储在对应的目录中。比如wyp表有dt和city两个分区,则对应dt=20131218,city=BJ对应表的目录为/user/hive/warehouse/dt=20131218/city=BJ,所有属于这个分区的数据都存放在这个目录中。

  创建分区表:

  ```

  create table t_partition(ts bigint,line string)

  partitioned by (dt string,country string)

  ROW FORMAT DELIMITED

  FIELDS TERMINATED BY ,;

  ```

  查看表结构:

  ```

  hive> desc t_partition;

  OK

  ts bigint

  line string

  dt string

  country string

   # Partition Information

   # col_name data_type comment

  dt string

  country string

  ```

  向表中导入数据:

  ```

  load data local inpath /home/centosm/test/file3.txt

  into table t_partition

  partition(dt=2022-04-01,country=US);

  ```

  数据导完后查询表中数据如下:

  ```

  hive> select * from t_partition;

  OK

  1111111 hello file1 2022-03-01 GB

  2222 hello file2 2022-03-01 GB

  123122222222 helloFile3 2022-04-01 CH

  123122222222 helloFile3 2022-04-01 US

  Time taken: 0.158 seconds, Fetched: 4 row(s)

  hive> select * from t_partition where country=US;

  OK

  123122222222 helloFile3 2022-04-01 US

  hive> select * from t_partition where country=US and dt=2022-04-01 ;

  OK

  123122222222 helloFile3 2022-04-01 US

  Time taken: 0.216 seconds, Fetched: 1 row(s)

  hive> select * from t_partition where country=US or dt=2022-03-01 ;

  OK

  1111111 hello file1 2022-03-01 GB

  2222 hello file2 2022-03-01 GB

  123122222222 helloFile3 2022-04-01 US

  Time taken: 0.13 seconds, Fetched: 3 row(s)

  ```

  查询表分区

  ```

  hive> show partitions t_partition;

  OK

  dt=2022-03-01/country=GB

  dt=2022-04-01/country=CH

  dt=2022-04-01/country=US

  Time taken: 0.074 seconds, Fetched: 3 row(s)

  ```

  查询hive存储数据的目录如下

  ```

  hadoop fs -ls /user/hive/warehouse/t_partition/dt=2022-03-01/country=GB

  Found 2 items

  -rwxr-xr-x 1 centosm supergroup 20 2022-03-25 01:11 /user/hive/warehouse/t_partition/dt=2022-03-01/country=GB/file.txt

  -rwxr-xr-x 1 centosm supergroup 17 2022-03-25 01:14 /user/hive/warehouse/t_partition/dt=2022-03-01/country=GB/file2.txt

  ```

  综上所述,分区只不过是将表中指定的文件存储到更细化的文件目录中,比如以时间为分区,那么每天的数据则会存储到以日期为目录的路径下,当进行查询时在sql中指定where那个分区时就不用进行全表查询,而是只需要查询某一天这个目录下的数据,很明显这么做大大地加快了查询的速度。

  ##### Bucket 桶表的基本相关概念

  - 对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。基本可以这么说分区表是粗粒度的划分,桶在细粒度的划分。当数据量比较大,我们需要更快的完成任务,多个map和reduce进程是唯一的选择。

  - 但是如果输入文件是一个的话,map任务只能启动一个。此时bucket table是个很好的选择,通过指定CLUSTERED的字段,将文件通过hash打散成多个小文件。

  - 把表(或者分区)组织成桶(Bucket)有两个理由:

   - 获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。

   - 使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。

  ###### 桶表的操作演示:

  ```

  创建桶表,我们使用CLUSTERED BY 子句来指定划分桶所有的列和划分的桶的个数。

  CREATE TABLE bucketed_user (id INT, name STRING)

  CLUSTERED BY (id) INTO 4 BUCKETS

  ROW FORMAT DELIMITED

  FIELDS TERMINATED BY ,;

  查看表结构

  desc bucketed_user;

   OK

   id int

   name string

   Time taken: 0.052 seconds, Fetched: 2 row(s)

  hive> select * from t_user;

   OK

   1 hello

   2 world

   3 java

   4 hadoop

   5 android

   6 hive

   7 hbase

   8 sqoop

   9 sqark

   1 hello

   2 world

   3 java

   4 hadoop

   5 android

   6 hive

   7 hbase

   8 sqoop

   9 sqark

   1 aaaa

   1 bbbb

   1 cccc

   1 dddd

  将t_user表数据加载到bucketed_user表中

  - 向这种带桶的表里面导入数据有两种方式,一种是外部生成的数据导入到桶表,一种是利用hive来帮助你生成桶表数据。

  - 由于hive在load数据的时候不能检查数据文件的格式与桶的 定义是否匹配,如果不匹配在查询的时候就会报错,所以最好还是让hive来帮你生成数据,简单来说就是利用现有的表的数据导入到新定义的带有桶的表中

  insert overwrite table bucketed_user

   select * from t_user;

  select * from bucketed_user;

   OK

   8 sqoop

   4 hadoop

   4 hadoop

   8 sqoop

   1 hello

   1 cccc

   1 bbbb

   1 aaaa

   9 sqark

   5 android

   1 dddd

   1 hello

   9 sqark

   5 android

   6 hive

   6 hive

   2 world

   2 world

   7 hbase

   3 java

   7 hbase

   3 java

  在hive仓库中的数据

  [centosm@centosm test]$hdfs dfs -ls /user/hive/warehouse/bucketed_user

   Found 4 items

   -rwxr-xr-x 1 centosm supergroup 17 2022-03-25 12:22 /user/hive/warehouse/bucketed_user/000000_0

   -rwxr-xr-x 1 centosm supergroup 26 2022-03-25 12:22 /user/hive/warehouse/bucketed_user/000001_0

   -rwxr-xr-x 1 centosm supergroup 15 2022-03-25 12:22 /user/hive/warehouse/bucketed_user/000002_0

   -rwxr-xr-x 1 centosm supergroup 15 2022-03-25 12:22 /user/hive/warehouse/bucketed_user/000003_0

   [centosm@centosm test]$

   [centosm@centosm test]$ hdfs dfs -cat /user/hive/warehouse/bucketed_user/000000_0

   8,sqoop

   4,hadoop

   4,hadoop

   8,sqoop

   [centosm@centosm test]$ hdfs dfs -cat /user/hive/warehouse/bucketed_user/000001_0

   1,hello

   1,cccc

   1,bbbb

   1,aaaa

   9,sqark

   5,android

   1,dddd

   1,hello

   9,sqark

   5,android

   [centosm@centosm test]$ hdfs dfs -cat /user/hive/warehouse/bucketed_user/000002_0

   6,hive

   6,hive

   2,world

   2,world

   [centosm@centosm test]$ hdfs dfs -cat /user/hive/warehouse/bucketed_user/000003_0

   7,hbase

   3,java

   7,hbase

   3,java

  运用tablesample 进行查询

  hive> select * from bucketed_user tablesample(bucket 1 out of 4 on id);;

  OK

  8 sqoop

  4 hadoop

  4 hadoop

  8 sqoop

  Time taken: 0.104 seconds, Fetched: 4 row(s)

  hive>

   > select * from bucketed_user tablesample(bucket 2 out of 4 on id);;

  OK

  1 hello

  1 cccc

  1 bbbb

  1 aaaa

  9 sqark

  5 android

  1 dddd

  1 hello

  9 sqark

  5 android

  Time taken: 0.067 seconds, Fetched: 10 row(s)

  hive>

   > select * from bucketed_user tablesample(bucket 3 out of 4 on id);;

  OK

  6 hive

  6 hive

  2 world

  2 world

  Time taken: 0.075 seconds, Fetched: 4 row(s)

  ablesample的作用就是让查询发生在一部分桶上而不是整个数据集上,上面就是查询4个桶里面第一个桶的数据;相对与不带桶的表这无疑是效率很高的,因为同样都是需要一小部分数据,但是不带桶的表需要使用rand()函数在整个数据集上检索。

  结论:由上述运行结果可以很明显得出分桶会将同一个用户id的文件放到同一个桶中,一个桶也会同时存在多个用户id的数据,例如/user/hive/warehouse/bucketed_user/000003_0 这个桶会存储所有id为3和7的数据。这样当我们要查询具体某一个id对应的所有的数据便可大大的缩小了查找的范围。

  ```

标签: 服务器