创建外部表

要创建外部表,请使用 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 移除其定义。

创建外部表后,分析其行数以提高查询性能。请参阅提高外部表的查询性能

必需的权限

除了在 Vertica 中拥有权限外,用户还必须拥有对外部数据的读取访问权限。

  • 对于本地磁盘上的数据,此访问权限由本地文件权限控制。

  • 对于 HDFS 中的数据,访问权限可能受 Kerberos 身份验证控制。请参阅访问已进行 Kerberize 的 HDFS 数据

  • 对于 S3 中的数据,您需要通过 AWS IAM 角色进行访问。请参阅S3 对象存储

对于 GCS 中的数据,您必须在读取数据之前启用 S3 兼容性。请参阅Google Cloud Storage (GCS) 对象存储

默认情况下,您还必须是数据库超级用户才能通过 SELECT 语句访问外部表。

在大多数情况下,要允许没有超级用户访问权限的用户查询外部表,则管理员必须创建一个 USER 存储位置,并为这些用户授予对该位置的读取访问权限。请参阅 CREATE LOCATIONGRANT(存储位置)。该位置必须是在创建外部表时 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)