内部表 | 外部表 | |
名称 | managed table | external table |
概念 | 创建表时,无external修饰 | 创建表时,被external修饰 |
数据管理 | Hive自身管理 | HDFS管理 |
数据保存位置 | 存储在元数据的位置 hive.metastore.warehouse.dir 默认为/user/hive/warehouse 不能任意 | hdfs中任意位置 |
删表时影响 | 直接删除元数据metadata以及数据存储 | 仅删除元数据,HDFS上的文件不会被删除 |
表结构修改时 | 会把结构修改信息同步到元数据(mysql里面) | 不会自动同步,需要手动修复 MSCK REPAIR TABLE xxx表 |
特性 | 只要HDFS里有结构化数据,如逗号分割的,我们都可以创建一个外部表,指向这个文件,然后通过hiveSql命令查询数据 |
分区表
随着表不断增大,对于新纪录的增删查操等操作,变得困难,对于差大型表,可以分为若干个小表,从而简化数据库的管理活动。
如,一天做一个分区。
- 数据是有规律的,如有一个时间字段,那么可以基于时间进行分区
- 简化后的小表称为一个分区。
- 分区实际上对于hdfs文件系统上的独立文件夹,该文件夹内是分区的数据
- 分区可以理解为分类,把不同类型的数据放到不同目录下
- 分类的标准是分区的字段,可以是一个,也可以是多个
- 意义:简化查询,查询时,尽量利用分区字段,减少查询范围。如果不使用分区字段,就会全部扫描
分区表例子 | |
建表 | 字段为:姓名、工资 CREATE TABLE test.employee ( name string, salary bigint ) partitioned by (date1 string) row format delimited FIELDS terminated BY ',' lines terminated BY '\n' stored AS textfile; 其中, partitioned by (date1 string) 是指使用date1字符串作为分区依据,从元数据角度,这个date1是一个字段 lines terminated BY '\n' 是指定换行符,默认就是'\n',如果有需要,可以改 从元数据角度,分区字段会作为一个字段 因为分区对于HDFS来说,是一个文件夹,因此我们看看建表后,HDFS结构是怎么样的: employee目录下,还没有子文件夹。说明分区还没创建。 |
准备数据 | zhang1,18000 zhang2,21000 值得注意,这个数据是没有时间字段信息的,也就是date1字段没有,这个文件直接load到hdfs里,会报错。 |
添加分区 | alter table employee add if not exists partition(date1='2022-05-01') 注:因为date1字段是字符串,因此这里用引号括起来 添加分区 表结构没变化。 查看HDFS文件夹 说明date1=2022-05-01这个分区已经建立了 再建立一个分区: alter table employee add if not exists partition(date1='2022-05-02') 又多了一个 因此alter table employee add if not exists partition的作用是,创建分区(生成实际的HDFS子目录) |
导入数据 | 两种方式: 1,hive命令行执行load,此时需要指定分区 load data local inpath '/usr/data2/program/hadoop/csv_import/employee.csv' into table test.employee partition(date1='2022-05-01'); 查看HDFS |
查看数据 | select * from test.employee; 注意观察, 放进去的文件并没有2022-05-01这个信息,hive自动为我们封装了这个date1字段 |
再导入一次,用方式2 | 使用Hadoop命令,需要指定目录 hadoop fs -put /usr/data2/program/hadoop/csv_import/employee.csv /user/hive/warehouse/test.db/employee/date1=2022-05-02/employee.csv 再查询一下: |
尝试通过HDFS直接创建分区 | 直接导入: 导入到2022-05-03 hadoop fs -put /usr/data2/program/hadoop/csv_import/employee.csv /user/hive/warehouse/test.db/employee/date1=2022-05-03/employee.csv 发现报错了: 因为目录没有创建 既然分区是目录,我们就可以手动创建这个hdfs目录 hadoop fs -mkdir /user/hive/warehouse/test.db/employee/date1=2022-05-03 然后再导入 hadoop fs -put /usr/data2/program/hadoop/csv_import/employee.csv /user/hive/warehouse/test.db/employee/date1=2022-05-03/employee.csv 再次查询 发现并未生效。 猜测是元数据里,没有这个分区的信息。查看Mysql里的元数据,显然没有2022-05-03这个分区, 所以放进去文件,也没有作用。 再补建分区: alter table employee add if not exists partition(date1='2022-05-03'); 元数据里有了。 再查询: 查到了。 说明:分区映射信息,是存储到了Mysql里。hive的分区依赖元数据里的PARTITIONS |
重复导入数据 | hdfs方式:会报错 load方式: 不会报错,会保存两份: /user/hive/warehouse/test.db/employee/date1=2022-05-01/employee.csv /user/hive/warehouse/test.db/employee/date1=2022-05-01/employee_copy_1.csv select 时: 数据会产生重复。 |
动态分区
在写入数据时,自动创建分区,包括目录结构
动态分区表例子 | |
建表 | 字段为:姓名、工资 CREATE TABLE test.employee2 ( name string, salary bigint ) partitioned by (date1 string) row format delimited FIELDS terminated BY ',' lines terminated BY '\n' stored AS textfile; |
导入数据 | insert into table test.employee2 partition(date1) select name,salary,date1 from test.employee; 这里,可以拆解为两部分,后面是一个查询,查询结果作用于前面 |
查询 | 数据按select name,salary,date1 from test.employee;插入到了employee2中。 |
注意: | 需要开启动态分区参数: 查看参数: set hive.exec.dynamic.partiion.mode; 如果不是nonstrict,则设置参数: set hive.exec.dynamic.partiion.mode=nonstrict; 备注: 因为的我设备是学习用的,所以我直接配置在hive-site.xml文件里了。 hive启动默认就开启了动态分区。 <property> <name>hive.exec.dynamic.partition.mode</name> <value>nonstrict</value> <description> In strict mode, the user must specify at least one static partition in case the user accidentally overwrites all partitions. In nonstrict mode all partitions are allowed to be dynamic. </description> </property> |
好处 | 避免手动创建分区,省事儿。 |
查看hadoop文件 | /user/hive/warehouse/test.db/employee2/date1=2022-05-01/000000_0 自动创建数据,文件名就不是employee.csv了,而是系统自动创建的000000_0且没有后缀。 cat一下 |
再次导入数据 | insert into table test.employee2 partition(date1) select name,salary,date1 from test.employee; 注意观察控制台显示信息: 再次查看2022-05-01的数据 发现生成了一个新文件 而不是在原来000000_0这个文件中追加。 查询: 数据是由两个文件构成 |