创建外部表
要创建外部表,请使用 CREATE EXTERNAL TABLE AS COPY 语句将表定义与复制语句结合起来。CREATE EXTERNAL TABLE AS COPY 使用来自 CREATE TABLE 和 COPY 的参数子集。
您可以使用 CREATE TABLE 像定义 Vertica 原生表一样定义表列。您还可以指定 COPY FROM 子句以描述如何读取数据,就像加载数据一样。如何指定 FROM 路径取决于文件所在的位置和数据格式。请参阅指定加载数据的位置和数据格式。
与原生表一样,您可以使用 INFER_TABLE_DDL 函数从支持格式的数据文件中派生列定义。
以下示例为存储在 HDFS 中的分隔数据定义了一个外部表:
=> CREATE EXTERNAL TABLE sales (itemID INT, date DATE, price FLOAT)
AS COPY FROM 'hdfs:///data/ext1.csv' DELIMITER ',';
以下示例使用存储在 S3 中的 ORC 格式的数据。数据有两个分区列。有关分区的详细信息,请参阅分区文件路径。
=> CREATE EXTERNAL TABLE records (id int, name varchar(50), created date, region varchar(50))
AS COPY FROM 's3://datalake/sales/*/*/*'
PARTITION COLUMNS created, region;
下面的示例演示了,如何才能从本地目录(没有分区和 glob)中的所有 Parquet 文件读取数据:
=> CREATE EXTERNAL TABLE sales (itemID INT, date DATE, price FLOAT)
AS COPY FROM '/data/sales/*.parquet' PARQUET;
创建外部表时,数据不会添加到数据库中,也不会创建投影。相反,Vertica 会对 CREATE EXTERNAL TABLE AS COPY 语句执行语法检查并在编录中存储表名称和 COPY 语句定义。每次 SELECT 查询引用外部表时,Vertica 将解析并执行存储的 COPY 语句以获取引用的数据。只有通过查询表才能发现表定义中的任何问题(例如不正确的列类型)。
若要从外部表成功返回数据,COPY 定义必须正确,其他依赖项(如文件、节点和其他资源)必须可供访问且在查询时可用。如果表定义使用 glob(通配符)并添加或删除文件,则外部表中的数据可以在查询之间更改。
ORC 和 Parquet 格式
为 ORC 或 Parquet 数据定义外部表时,您必须定义文件中的所有数据列。如果省略数据列,则使用该表的查询会因错误而中止。
如果您在同一 COPY 语句中从多个 ORC 或 Parquet 文件加载,并且其中任何一个被中止,则整个加载中止。这种行为与分隔文件的行为不同,分隔文件中的 COPY 语句会加载其可以加载的数据并忽略剩余数据。
外部表的特殊注意事项
如果列的最大长度小于实际数据(如过短的 VARCHAR),Vertica 会将数据截断并记录该事件。
如果列上的约束导致值被拒绝,您可能会看到意外的查询结果:
-
如果您指定 NOT NULL 列约束并且数据包含 null 值,则这些行将被拒绝。
-
如果您使用 ENFORCELENGTH,太长的值将被拒绝而不是被截断。
-
读取 ORC 数据时,如果声明了标量精度并且某些数据不适合,则该行将被拒绝。例如,如果将列指定为 Decimal(6,5),则拒绝值 123.456。
了解列约束是否导致数据被拒绝的一种方法是,列上的 COUNT 返回的值是否与 COUNT(*) 不同。
使用 COPY 参数 ON ANY NODE 时,请确认源文件定义在所有节点上均相同。指定不同的外部文件会导致生成的结果不一致。
可以利用分区来限制 Vertica 读取的数据量。有关使用分区数据的详细信息,请参阅分区文件路径。
取消 CREATE EXTERNAL TABLE AS COPY 语句会导致不可预测的结果。如果您在开始操作后发现表定义不正确(例如,无意中指定了错误的外部位置),请等待查询完成。当外部表存在时,使用 DROP TABLE 移除其定义。
提示
使用新的外部数据源时,请考虑将 REJECTMAX 设置为 1 以使数据中的问题明显。以这种方式进行测试可以让您在针对数据运行生产查询之前发现数据中的问题。创建外部表后,分析其行数以提高查询性能。请参阅提高外部表的查询性能。
必需的权限
除了在 Vertica 中拥有权限外,用户还必须拥有对外部数据的读取访问权限。
-
对于本地磁盘上的数据,此访问权限由本地文件权限控制。
-
对于 HDFS 中的数据,访问权限可能受 Kerberos 身份验证控制。请参阅访问已进行 Kerberize 的 HDFS 数据。
-
对于 S3 中的数据,您需要通过 AWS IAM 角色进行访问。请参阅S3 对象存储。
对于 GCS 中的数据,您必须在读取数据之前启用 S3 兼容性。请参阅Google Cloud Storage (GCS) 对象存储。
默认情况下,您还必须是数据库超级用户才能通过 SELECT 语句访问外部表。
在大多数情况下,要允许没有超级用户访问权限的用户查询外部表,则管理员必须创建一个 USER 存储位置,并为这些用户授予对该位置的读取访问权限。请参阅 CREATE LOCATION 和 GRANT(存储位置)。该位置必须是在创建外部表时 COPY 语句中使用的路径的父项。此要求不适用于 HDFS 中存储的外部表。以下示例显示了为一个名为 Bob 的用户授予对数据位于 /tmp
(包含任何深度的子目录)之下的所有外部表的访问权限:
=> CREATE LOCATION '/tmp' ALL NODES USAGE 'user';
=> GRANT ALL ON LOCATION '/tmp' to Bob;
组织外部表数据
如果存储在外部表中的数据定期更改(例如每月存储最近的历史数据),您可以结合使用分区和通配符 (globs),更加动态地解析存储的 COPY 语句定义。例如,如果将每月数据存储在 NFS 挂载上,您可以在日历年的顶层目录中按月组织文件,例如:
/year=2018/month=01/
然后,您可以从 COPY 语句的目录名称中读取年份和月份值:
=> CREATE EXTERNAL TABLE archive (...) AS COPY FROM '/nfs_name/*/*/*' PARTITION COLUMNS year, month;
每当 Vertica 查询引用外部表 archive
并且 Vertica 解析 COPY 语句时,查询都可以访问顶级 monthly
目录中存储的所有数据。如果查询按年份或月份筛选(例如在 WHERE 子句中),则 Vertica 在评估 glob 时会跳过不相关的目录。有关详细信息,请参阅分区文件路径。
验证表定义
创建外部表时,Vertica 会验证 CREATE EXTERNAL TABLE AS COPY FROM 语句的语法。例如,如果在语句中忽略必需的关键字,则创建外部表会失败:
=> CREATE EXTERNAL TABLE ext (ts timestamp, d varchar)
AS COPY '/home/dbadmin/designer.log';
ERROR 2778: COPY requires a data source; either a FROM clause or a WITH SOURCE for a user-defined source
系统不会检查 COPY 定义的其他组件(例如路径语句和节点可用性),直到 SELECT 查询引用外部表。
若要验证外部表定义,请运行引用外部表的 SELECT 查询。检查返回的查询数据是否符合预期。如果查询没有正确地返回数据,请检查 COPY 异常以及拒绝数据日志文件。
由于 COPY 定义确定了查询外部表时发生的内容,因此 COPY 语句错误可以揭示潜在问题。有关 COPY 异常和拒绝的详细信息,请参阅处理杂乱的数据。
查看外部表定义
创建外部表时,Vertica 将在 TABLES 系统表的 table_definition 列中存储 COPY 定义语句。
要列出所有表,请使用 SELECT * 查询,如下所示:
=> SELECT * FROM TABLES WHERE table_definition <> '';
使用如下所示的查询列出外部表定义:
=> SELECT table_name, table_definition FROM TABLES;
table_name | table_definition
------------+----------------------------------------------------------------------
t1 | COPY FROM 'TMPDIR/external_table.dat' DELIMITER ','
t1_copy | COPY FROM 'TMPDIR/external_table.dat' DELIMITER ','
t2 | COPY FROM 'TMPDIR/external_table2.dat' DELIMITER ','
(3 rows)