HiveQL数据定义
2016-03-14 00:08
190 查看
Hive中的数据库
Hive中数据库的概念本质上仅仅是表的一个目录或者命名空间。然而,对于具有很多组和用户的大集群来说,这时非常有用的,因为这样可以避免表命名冲突。通常会使用数据库来将生产表组织成逻辑组。如果用户没有显式指定数据库,那么将会使用默认的数据库default。
下面这个例子就展示了如何创建一个数据库:
hive> CREATE DATABASE financials;
如果数据库financials已经存在的话,那么将会抛出一个错误信息。使用如下语句可以避免在这种情况下抛出错误信息:
hive> CREATE DATABASE IF NOT EXISTS financials;
随时可以通过如下命令查看Hive中所包含的数据库:
hive> SHOW DATABASES;
如果数据库非常多的话,那么可以使用正则表达式匹配来筛选出需要的数据库名。下面这个例子展示的是列举出所有的以字母h开头,以其他字符结尾(即.*部分含义)的数据库名:
hive> SHOW DATABASES LIKE 'h.*';
Hive会为每个数据库创建一个目录。数据库中的表将会以这个数据库目录的子目录形式存储。有一个例外就是default数据库中的表,因为这个数据库本身没有自己的目录。
数据库所在的目录位于属性hive.metastore.warehouse.dir所指定的顶层目录之后。假设用户使用的是这个配置项默认的配置,也就是/user/hive/warehouse那么当我们创建数据库financials时,Hive将会对应地创建一个目录/user/hive/warehouse/financials.db。这里请注意,数据库的文件目录名是以.db结尾的。
用户可以通过如下命令来修改这个默认的位置:
hive> CREATE DATABASE financials LOCATION '/my/dir';
用户也可以为这个数据库增加一个描述信息,这样通过DESCRIBE DATABASE <database>命令就可以查看到该信息。
hive> CREATE DATABASE financials > COMMENT 'Holds all financial tables'; hive> DESCRIBE DATABASE financials; financials Holds all financial tables hdfs://master-server/user/hive/warehouse/financials.db hadoop USER
从上面的例子中,我们可以注意到,DESCRIBE DATABASE语句也会显示出这个数据库所在的文件目录位置路径。在这个例子中,URI格式是hdfs。如果安装的是MapR,那么这里就应该是maprfs。对于亚马逊弹性MapReduce(EMP)集群,这里应该是hdfs,但是用户可以设置hive.metastore.warehouse.dir为亚马逊S3特定的格式(例如,属性值设置为s3n://bucketname…)。用户可以使用s3作为模式,但是如果使用规则s3n会更好。
前面DESCRIBE DATABASE语句输出中,我们使用了master-server来代表URI权限,也就是说应该是由文件系统的”主节点”(例如,HDFS中运行NameNode服务的那台服务器)的服务器名加上一个可选的端口号构成的(例如,服务器名:端口号这样的格式)。如果用户执行的是伪分布式模式,那么主节点服务器名称就应该是localhost。对于本地模式这个路径应该是一个本地路径,例如:file:///user/hive/warehouse/financials.db。
如果这部分信息省略了,那么Hive将会使用Hadoop配置文件中的配置项fs.default.name作为master-server所对应的服务器名和端口号,这个配置文件可以在$HADOOP_HOME/conf这个目录下找到。
需要明确的是,hdfs:///user/hive/warehouse/financials.db和hdfs://master-server/user/hive/warehouse/financials.db是等价的,其中master-server是主节点的DNS名和可选的端口号。
为了保持完整性,当用户指定一个相对路径(例如,some/relative/path)时,对于HDFS和Hive,都会将这个相对路径放到分布式文件系统的指定根目录下(例如,hdfs:///user/<user-name>)。然而,如果用户是在本地模式下执行的话,那么当前的本地工作目录将是some/relative/path的父目录。
为了脚本的可移植性,通常会省略掉那个服务器和端口号信息,而只有在涉及到另一个分布式文件系统实例(包括S3存储)的时候才会指明该信息。
此外,用户还可以为数据库增加一些和其相关的键-值对属性信息,可以通过DESCRIBE DATABASE EXTENDED <database>语句显示出这些信息:
hive> CREATE DATABASE financials > WITH DBPROPERTIES ('creator' = 'universe', 'date' = '2016-03-13'); hive> DESCRIBE DATABASE financials; financials hdfs://localhost:9000/user/hive/warehouse/financials.dbhadoop USER hive> DESCRIBE DATABASE EXTENDED financials; financials hdfs://localhost:9000/user/hive/warehouse/financials.dbhadoop USER {date=2016-03-13, creator=universe}
USE命令用于将某个数据库设置为用户当前的工作数据库,和在文件系统中切换工作目录是一个概念:
hive> USE financials;
现在使用像SHOW TABLES这样的命令就会显示当前这个数据库下所有的表。
不幸的是,并没有一个命令可以让用户查看当前所在的是哪个数据库!幸运的是,在Hive中是可以重复使用USE…命令的,这是因为在Hive中并没有嵌套数据库的概念。
其实,可以通过设置一个属性值来在提示符里面显示当前所在的数据库:
hive> set hive.cli.print.current.db=true; hive (financials)> USE default; hive (default)> set hive.cli.print.current.db=false; hive>
最后,用户可以删除数据库:
hive> DROP DATABASE IF EXISTS financials;
IF EXISTS子句是可选的,如果加了这个子句,就可以避免因数据库financials不存在而抛出警告信息。
默认情况下,Hive是不允许用户删除一个包含有表的数据库的。用户要么先删除数据库中的表,然后再删除数据库;要么在删除命令的最后面加上关键字CASCADE,这样可以使Hive自行先删除数据库中的表:
hive> DROP DATABASE IF EXISTS financials CASCADE;
如果使用的是RESTRICT这个关键字而不是CASCADE这个关键字的话,那么就和默认情况一样,也就是,如果想删除数据库,那么必须先要删除掉该数据库中的所有表。如果某个数据库被删除了,那么其对应的目录也同时会被删除。
修改数据库
用户可以使用ALTER DATABASE命令为某个数据库的DBPROPERTIES设置键-值对属性值,来描述这个数据库的属性信息。数据库的其他元数据信息都是不可更改的,包括数据库名和数据库所在的目录位置:hive> ALTER DATABASE financials SET DBPROPERTIES ('edited-by'='Joe Dba');
创建表
CREATE TABLE语句遵从SQL语法惯例,但是Hive的这个语句中具有显著的功能扩展,使其可以具有更广泛的灵活性。例如,可以定义表的数据文件存储在什么位置、使用什么样的存储格式,等等。一个具体的示例如下:hive> CREATE DATABASE IF NOT EXISTS mydb; OK hive> CREATE TABLE IF NOT EXISTS mydb.employees ( > name STRING COMMENT 'Employee name', > salary FLOAT COMMENT 'Employee salary', > subordinates ARRAY<STRING> COMMENT 'Names of subordinates', > deductions MAP<STRING, FLOAT> COMMENT 'Keys are deductions names, values are percentages', > address STRUCT<street:STRING, city:STRING, state:STRING, zip:INT> COMMENT 'Home address') > COMMENT 'Description of the table' > LOCATION '/user/hive/warehouse/mydb.db/employees' > TBLPROPERTIES('creator'='me', 'created_at'='2016-03-13 23:39:13'); OK
首先,我们可以注意到,如果用户当前所处的数据库并非是目标数据库,那么用户是可以在表名前增加一个数据库名来进行指定的,也就是例子中的mydb。
如果用户增加上可选项IF NOT EXISTS,那么若表已经存在了,Hive就会忽略掉后面的执行语句,而且不会有任何提示。在那些第一次执行时需要创建表的脚本中,这么写是非常有用的。
然而这个语句还有一个用户需要注意的问题。如果用户所指定的表模式和已经存在的这个表的模式不同的话,Hive不会对此作出提示。如果用户的意图是使这个表具有重新指定的那个新的模式的话,那么就需要先删除这个表,也就是丢弃之前的数据,然后重建这张表。用户可以考虑使用一个或多个ALTER TABLE语句来修改已经存在的表的结构。
用户可以在字段类型后为每个字段增加一个注释。和数据库一样,用户也可以为这个表本身添加一个注释。
用户可以根据情况为表中的数据指定一个存储路径(和元数据截然不同的是,元数据总是会保存这个路径)。在这个例子中,我们使用的Hive将会使用默认的路径/user/hive/warehouse/mydb.db/employees。其中,/user/hive/warehouse是默认的”数据仓库”路径地址,mydb.db是数据库目录,employees是表目录。
默认情况下,Hive总是将创建的表的目录放置在这个表所属的数据库目录之后。不过,default数据库是个例外,其在/user/hive/warehouse下并没有对应一个数据库目录。因此,default数据库中的表目录会直接位于/user/hive/warehouse目录之后(除非用户明确指定为其他路径)。
还可以自定义一个或多个表属性。大多数情况下,TBLPROPERTIES的主要作用是按键-值对的格式为表增加额外的文档说明。但是,当我们检查Hive和像DymamoDB这样的数据库间的集成时,我们可以发现TBLPROPERTIES还可用作表示关于数据库连接的必要的元数据信息。
Hive会自动增加两个表属性:一个是last_modified_by,其保存最后修改这个表的用户的用户名;另一个是last_modified_time,其保存最后一次修改的新纪元时间秒。可以通过下面命令查看属性信息:
hive> SHOW TBLPROPERTIES mydb.employees; OK comment Description of the table created_at 2016-03-13 23:39:13 creator me transient_lastDdlTime 1457884102
用户还可以拷贝一张已经存在的表的表模式(而无需拷贝数据):
hive> CREATE TABLE IF NOT EXISTS mydb.employee2 LIKE mydb.employees;
SHOW TABLES命令可以列举出所有的表。如果不增加其他参数,那么只会显示当前工作数据库下的表。如:
hive> USE mydb; hive> SHOW TABLES; employee2 employees
即使不在那个数据库下,我们也可以列举指定数据库下的表的:
hive> USE default; hive> SHOW TABLES IN mydb; employee2 employees
如果我们有很多表,那么我们可以使用正则表达式来过滤出所需要的表名。如:
hive> USE mydb; hive> SHOW TABLES 'empl.*'; employee2 employees
Hive并非支持所有的正则表达式功能。如果用户了解正则表达式的话,最好事先测试下备选的正则表达式是否真正奏效。
单引号中的正则表达式表示的是选择所有以empl开头并以其他任意字符(也就是.*部分)结尾的表名。
我们也可以使用DESCRIBE EXTENDED mydb.employees命令来查看这个表的详细表结构信息。(如果当前所处的工作数据库就是mydb的话,那么可以不加mydb.这个前缀)。
使用FORMATTED关键字替代EXTENDED关键字的话,即SHOW FORMATTED mydb.employees命令,可以提高更加可读的和冗长的输出信息。
如果用户只想查看某一列的信息,那么只要在表名后增加这个字段的名称即可。这种情况下,使用EXTENDED关键字也不会增加更多的输出信息:
hive> DESCRIBE employees.name; name string from deserializer
管理表
目前所创建的表都是所谓的管理表,有时也被称为内部表。因为这种表,Hive会(或多或少地)控制着数据的生命周期。正如所看到的,Hive默认情况下会将这些表的数据存储在由配置项hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定义的目录的子目录下。当我们删除一个管理表时,Hive也会删除这个表中数据。
但是,管理表不方便和其他工作共享数据。例如,假设我们拥有一份由Pig或者其他工具创建并且主要由这一工具使用的数据,同时我们还想使用Hive在这份数据上执行一些查询,可是并没有给予Hive对数据的所有权,我们可以创建一个外部表指向这份数据,而并不需要对其具有所有权。
外部表
假设数据文件位于分布式文件系统的/data/socks目录下。下面的语句将创建一个外部表,其可以读取所有位于/data/stocks目录下的以逗号符分隔的数据:hive> CREATE EXTERNAL TABLE IF NOT EXISTS stocks ( > index INT, > source INT, > destination INT, > cost INT) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY ',' > LOCATION '/home/hadoop/workspace';
关键字EXTERNAL告诉Hive这个表是外部的,而后面的LOCATION…子句则用于告诉Hive数据位于哪个路径下。
因为表是外部的,所以Hive并非完全拥有这份数据。因此,删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。
管理表和外部表有一些小小的区别,那就是,有些HiveQL语法结构并不适用于外部表。
然而,我们需要清楚的重要的一点是管理表和外部表之间的差异要比刚开始所看到的小得多。即使对于管理表,用户也是可以知道数据是位于哪个路径下的,因此用户也是可以使用其他工具(例如Hadoop的dfs命令等)来修改甚至删除管理表所在的路径目录下的数据的。可能从严格意义上来说,Hive是管理着这些目录和文件,但是其并非具有对它们的完全控制权限。
如果数据会被多个工具共享,那么可以创建一个外部表,来明确对数据的所有权。
用户可以在DESCRIBE EXTENDED tablename语句的输出中查看到表是否是管理表或者外部表。在末尾的详细表信息输出中,对于管理表,用户可以看到如下信息:
… tableType:MANAGED_TABLE)
对于外部表,用户可以查看到如下信息:
… tableType:EXTERNAL_TABLE)
对于管理表,用户还可以对一张存在的表进行表结构复制(而不会复制数据):
hive> CREATE EXTERNAL TABLE IF NOT EXISTS mydb.employees3 > LIKE mydb.employees > LOCATION '/path/to/data';
提示:这里如果省略掉EXTERNAL关键字而且源表是外部表的话,那么生成的新表也将是外部表。如果语句中省略EXTERNAL关键字而且源表是管理表的话,那么生成的新表也将是管理表。但是如果语句中包含有EXTERNAL关键字而且源表是管理表的话,那么生成的新表将是外部表。在这场景下,LOCATION子句同样是可选的。
分区表、管理表
数据分区的一般概念存在已久。其可以有多种形式,但是通常使用分区来水平分散压力,将数据从物理上转移到和使用最频繁的用户更近的地方,以及实现其他目的。Hive中有分区表的概念。我们可以看到分区表具有重要的性能优势,而且分区表还可以将数据以一种符合逻辑的方式进行组织,比如分层存储。
看下面的例子:
CREATE TABLE employees ( name STRING, salary FLOAT, subordinates ARRAY<STRING>, deductions MAP<STRING, FLOAT>, address STRUCT<street:STRING, city:STRING, state:STRING, zip:INT> ) PARTITIONED BY (country STRING, state STRING);
分区表改变了Hive对数据存储的组织方式。如果我们是在mydb数据库中创建的这个表,那么对于这个表只会有一个employees目录与之对应:
hdfs://master-server/user/hive/warehouse/mydb.db/employees
但是,Hive现在将会创建好可以反映分区表结构的子目录。例如:
…… ……/employees/country=CA/state=AB ……/employees/country=CA/state=BC …… ……/employees/country=US/state=AL ……/employees/country=US/state=AK ……
州目录下将会包含有零个或多个文件,这些文件中存储着那些州的雇员信息。
例如,下面这个查询语句将会查找出在美国伊利诺斯州的所有雇员:
SELECT * FROM employees WHERE country = 'US' AND state = 'IL';
需要注意的是,因为country和state的值已经包含在文件目录名称中了,所以也就没有必要将这些值存放到它们目录下的文件中了。事实上,数据只能从这些文件中获得,因此用户需要在表的模式中说明这点,而且这个数据浪费空间。
对数据进行分区,也许最重要的原因就是为了更快的查询。
当我们在WHERE子句中增加谓词来按照分区值进行过滤时,这些谓词被称为分区过滤器。
如果表中的数据以及分区个数都非常大的话,执行一个包含有所有分区的查询可能会出发一个巨大的MapReduce任务。一个高度建议的安全措施是将Hive设置为“strict(严格)”模式,这样如果对分区表进行查询而WHERE子句没有加分区过滤的话,将会禁止提交这个任务。用户可以按照下面的语句将属性值设置为“nonstrict(非严格的)”:
hive> set hive.mapred.mode=strict; hive> SELECT e.name, e.salary FROM employees e LIMIT 100; FAILED: Error in semantic analysis: No partition predicate found for Alias "e" Table "employees" hive> set hive.mapred.mode=nonstrict; hive> SELECT e.name, e.salary FROM employees e LIMIT 100; John Doe 100000.0 ……
可以通过SHOW PARTITIONS命令查看表中存在的所有分区。
如果表中现在存在很多的分区,而用户只想查看存储某个特定分区键的分区的话,可以在这个命令上增加一个指定了一个或者多个特定分区字段值的PARTITION子句,进行过滤查询:
hive> SHOW PARTITIONS employees PARTITION(country='US'); hive> SHOW PARTITIONS employees PARTITION(country='US', state='AK');
DESCRIBE EXTENDED employees命令也会显示出分区键。
在管理表中用户可以通过载入数据的方式创建分区。如下例中的语句在从一个本地目录($HOME/california-employees)载入数据到表中的时候,将会创建一个US和CA(表示加利福尼亚州)分区。用户需要为每个分区字段指定一个值。请注意在HiveQL中是如何引用HOME环境变量的:
LOAD DATA LOCAL INPATH '${env:HOME}/california-employees' INTO TABLE employees PARTITION (country = 'US', state = 'CA');
Hive将会创建这个分区对应的目录…/employees/country=US/state=CA,而且$HOME/california-employees这个目录下的文件将会拷贝到上述分区目录下。
删除表
Hive支持和SQL中DROP TABLE命令相似的操作:DROP TABLE IF EXISTS employees;
可以选择是否使用IF EXISTS关键字。如果没有使用这个关键字而且表并不存在的话,那么将会抛出一个错误信息。
对于管理表,表的元数据信息和表内的数据都会被删除。
对于外部表,表的元数据信息会被删除,但是表中的数据不会被删除。
修改表
大多数的表属性可以通过ALTER TABLE语句进行修改。这些操作会修改元数据,但不会修改数据本身。这些语句可用于修改表模式中出现的错误、改变分区路径,以及其他一些操作。表重命名
ALTER TABLE log_messages RENAME TO logmsgs;
增加、修改和删除表分区
ALTER TABLE log_messages ADD IF NOT EXISTS PARTITION (year=2011, month=1, day=1) LOCATION '/logs/2011/01/01' PARTITION (year=2011, month=1, day=2) LOCATION '/logs/2011/01/02';
ALTER TABLE log_messages PARTITION(year=2011, month=01, day=02) SET LOCATION 's3n://outbucket/logs/2011/01/02';
ALTER TABLE log_messages DROP IF EXISTS PARTITION(year=2011, month=12, day=2);
修改列信息
ALTER TABLE log_messages CHANGE COLUMN hms hours_minute_seconds INT COMMENT 'The hours, minutes, and seconds part of the timestamp' AFTER severity;
关键字COLUMN和COMMENT子句是可选的。AFTER severity语句的意思是,将字段转移到severity字段之后。
增加列
ALTER TABLE log_messages ADD COLUMNS( app_name STRING COMMENT 'Application name', session_id LONG COMMENT 'Current session id');
删除或者替换列
下面这个例子移除了之前所有的字段并重新指定了新的字段:ALTER TABLE log_messages REPLACE COLUMNS ( hours_min_secs INT COMMENT 'Timestamp', severity STRING 'Message severity', message STRING 'Message');
修改表属性
ALTER TABLE log_messages SET TBLPROPERTIES ( 'notes' = 'The process id is no longer captured; this column is always NULL');
修改表存储属性
ALTER TABLE log_messages PARTITION(year=2012, month=1, day=1) SET FILEFORMAT SEQUENCEFILE;
ALTER TABLE table_using_JSON_storage SET SERDE 'com.example.JSONSerDe' WITH SERDEPROPERTIES ( 'prop1' = 'value1', 'prop2' = 'value2' );
相关文章推荐
- 3月9日高项作业
- 配置Tomcat
- Cutecom--Linux下串口调试工具
- 宏的多种用法与简介
- Java微信公众平台开发(8) 多媒体消息回复
- Java微信公众平台开发(10) 微信自定义菜单的创建实现
- Java微信公众平台开发(9) 关键字回复以及客服接口实现
- JSP自定义标签简单入门教程
- Python使用multiprocessing实现一个最简单的分布式作业调度系统
- 实例讲解Python中函数的调用与定义
- PHP访问数据库集群的方法小结
- Zend Framework教程之资源(Resources)用法实例详解
- 如何解决PHP使用mysql_query查询超大结果集超内存问题
- Zend Framework教程之Bootstrap类用法概述
- Zend Framework自定义Helper类相关注意事项总结
- Zend Framework教程之Application用法实例详解
- YII Framework教程之异常处理详解
- YII Framework框架教程之日志用法详解
- YII Framework框架教程之安全方案详解
- YII Framework框架教程之缓存用法详解