更新类型
本主题介绍了无需实际更改数据即可在 CREATE
TABLE
语句中对架构进行的一些更改。我们将介绍每种架构更新类型,并指定哪些数据格式允许在 Athena 中实现这些更新。要更新架构,在某些情况下可以使用 ALTER TABLE
命令;而在其他情况下,实际上并不需要修改现有表。而是使用新名称创建一个表,该表修改了在原始 CREATE TABLE
语句中使用的架构。
根据您期望架构的演进方式,选择一种兼容的数据格式,以继续使用 Athena 查询。
考察一个应用程序,该应用程序从 orders
表中读取订单信息,而该表存在两种格式:CSV 和 Parquet。
以下示例用 Parquet 格式创建一个表:
CREATE EXTERNAL TABLE orders_parquet ( `orderkey` int, `orderstatus` string, `totalprice` double, `orderdate` string, `orderpriority` string, `clerk` string, `shippriority` int ) STORED AS PARQUET LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_ parquet/';
以下示例用 CSV 格式创建同样的表:
CREATE EXTERNAL TABLE orders_csv ( `orderkey` int, `orderstatus` string, `totalprice` double, `orderdate` string, `orderpriority` string, `clerk` string, `shippriority` int ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_csv/';
在以下部分中,我们将介绍这些表的更新如何影响 Athena 查询。
将列添加到表的开头或中间
添加列是最常见的架构变化之一。例如,您可以添加新列,用新的数据来充实表。或者,如果一个现有列的源发生了变化,您可以添加一个新列,同时保留该列表的前一版本,以调整依赖它们的应用程序。
要将列添加到表的开头或中间,并继续针对现有表运行查询,请使用 AVRO、JSON 以及 Parquet 和 ORC(如果它们的 SerDe 属性设为按名称读取)。有关信息,请参阅ORC 和 Parquet 中的索引访问。
不要在 CSV 和 TSV 表的开头或中间添加列,因为这些格式取决于排序。如果在这些情况下添加列,分区架构改变将导致架构不匹配的错误。
以下示例创建了一个新表,该表基于 JSON 数据在表的中间添加了一个 o_comment
列。
CREATE EXTERNAL TABLE orders_json_column_addition ( `o_orderkey` int, `o_custkey` int, `o_orderstatus` string, `o_comment` string, `o_totalprice` double, `o_orderdate` string, `o_orderpriority` string, `o_clerk` string, `o_shippriority` int, ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_json/';
在表的末尾添加列
如果您使用 Athena 支持的任意格式(例如 Parquet、ORC、Avro、JSON、CSV 和 TSV)创建表,则可使用 ALTER TABLE ADD COLUMNS
语句在现有列之后但在分区列之前添加列。
以下示例在 orders_parquet
表末尾的任何分区列之前添加一个 comment
列:
ALTER TABLE orders_parquet ADD COLUMNS (comment string)
注意
要在运行 ALTER
TABLE ADD COLUMNS
后在 Athena 查询编辑器中查看新的表列,请手动刷新编辑器中的表列表,然后重新展开表。
删除列
如果表中的列不再包含数据,您可能需要删除它们,或者,您可能需要限制对于列数据的访问。
-
您可以从 JSON、Avro 表,以及按名称读取的 Parquet 和 ORC 表中删除列。有关信息,请参阅ORC 和 Parquet 中的索引访问。
-
如果您希望保留已在 Athena 中创建的表,我们不建议从 CSV 和 TSV 表中删除列。删除列会破坏架构,需要您重新创建不包含已删除列的表。
在本示例中,将从 Parquet 表中删除一列`totalprice`
并运行查询。在 Athena 中,Parquet 默认是按名称读取的,因此我们省略了指定按名称读取的 SERDEPROPERTIES 配置。请注意,即使更改了架构,以下查询也会成功:
CREATE EXTERNAL TABLE orders_parquet_column_removed ( `o_orderkey` int, `o_custkey` int, `o_orderstatus` string, `o_orderdate` string, `o_orderpriority` string, `o_clerk` string, `o_shippriority` int, `o_comment` string ) STORED AS PARQUET LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_parquet/';
重命名列
有时,您可能需要重命名表列,以便纠正拼写、让列名称含义更清晰或重用现有列以避免列重新排序。
如果将数据存储为 CSV 和 TSV,或 Parquet 和 ORC(配置为按索引读取),则可以将列重新命名。有关信息,请参阅ORC 和 Parquet 中的索引访问。
Athena 会按照架构中的列顺序读取 CSV 和 TSV 数据并以同样的顺序返回。它不会使用列名称来将数据映射到列,因此,如果不中断 Athena 查询,您就可以重命名 CSV 或 TSV 格式列。
重命名列的一种策略是基于相同的基础数据创建新表,但使用新的列名。以下示例会创建一个名为 orders_parquet_column_renamed
新 orders_parquet
表。该示例将列 `o_totalprice`
名称更改为 `o_total_price`
,然后在 Athena 中运行查询:
CREATE EXTERNAL TABLE orders_parquet_column_renamed ( `o_orderkey` int, `o_custkey` int, `o_orderstatus` string, `o_total_price` double, `o_orderdate` string, `o_orderpriority` string, `o_clerk` string, `o_shippriority` int, `o_comment` string ) STORED AS PARQUET LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_parquet/';
对于 Parquet 表而言,以下查询可以运行,但经过重命名的列不会显示数据,因为列是按名称访问的(Parquet 的默认设置)而不是按索引访问的:
SELECT * FROM orders_parquet_column_renamed;
对于 CSV 表的查询看起来类似:
CREATE EXTERNAL TABLE orders_csv_column_renamed ( `o_orderkey` int, `o_custkey` int, `o_orderstatus` string, `o_total_price` double, `o_orderdate` string, `o_orderpriority` string, `o_clerk` string, `o_shippriority` int, `o_comment` string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_csv/';
对于 CSV 表而言,以下查询可以运行,并将显示所有列的数据,包括经过重新命名的列:
SELECT * FROM orders_csv_column_renamed;
重新排序列
只有表的数据格式是按名称读取的,才可以将列重新排序,例如 JSON 或默认为按名称读取的 Parquet。如有需要,也可以将 ORC 设为按名称读取。有关信息,请参阅ORC 和 Parquet 中的索引访问。
以下示例创建了一个新表,其中的列顺序不同:
CREATE EXTERNAL TABLE orders_parquet_columns_reordered ( `o_comment` string, `o_orderkey` int, `o_custkey` int, `o_orderpriority` string, `o_orderstatus` string, `o_clerk` string, `o_shippriority` int, `o_orderdate` string ) STORED AS PARQUET LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_parquet/';
更改列的数据类型
当现有类型无法再容纳所需的信息量时,您可能需要使用其他列类型。例如,ID 列的值可能超过 INT
数据类型的大小,需要使用 BIGINT
数据类型。
在计划为列使用不同的数据类型时,请考虑以下几点:
-
在大多数情况下,不能直接更改列的数据类型。而是可以重新创建 Athena 表,并使用新的数据类型定义该列。
-
只有特定数据类型可以读取为其他数据类型。有关可以进行这种处理的数据类型,请参阅本部分中的表。
-
对于 Parquet 和 ORC 格式的数据,如果表未进行分区,则将无法为列使用其他数据类型。
-
对于 Parquet 和 ORC 格式的分区表,一个分区的列类型可以不同于另一个分区的列类型,而且 Athena 将
CAST
为所需的类型(如果可能)。有关信息,请参阅避免带有分区的表出现架构不匹配错误。 -
对于仅使用 LazySimpleSerDe 创建的表,可以使用
ALTER TABLE REPLACE COLUMNS
语句将现有列替换为不同的数据类型,但是还必须在语句中重新定义要保留的所有现有列,否则它们将被删除。有关更多信息,请参阅 ALTER TABLE REPLACE COLUMNS。 -
仅对于 Apache Iceberg 表而言,您可以使用 ALTER TABLE CHANGE COLUMN 语句更改列的数据类型。
ALTER TABLE REPLACE COLUMNS
不支持 Iceberg 表。有关更多信息,请参阅 不断变化的 Iceberg 表架构。
重要
我们强烈建议您在执行数据类型转换时,先测试和验证一下您的查询。如果 Athena 无法使用目标数据类型,则 CREATE
TABLE
查询可能会失败。
下表列出了被视为其他数据类型的数据类型:
兼容的数据类型 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
原始数据类型 | 可用的目标数据类型 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
STRING |
BYTE , TINYINT , SMALLINT ,
INT , BIGINT |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BYTE |
TINYINT , SMALLINT , INT ,
BIGINT |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TINYINT |
SMALLINT , INT , BIGINT |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SMALLINT |
INT , BIGINT |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
INT |
BIGINT |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FLOAT |
DOUBLE |
以下示例为原始 orders_json
表使用 CREATE TABLE
语句创建一个名为 orders_json_bigint
的新表。新表使用 BIGINT
而不是 INT
作为 `o_shippriority`
列的数据类型。
CREATE EXTERNAL TABLE orders_json_bigint ( `o_orderkey` int, `o_custkey` int, `o_orderstatus` string, `o_totalprice` double, `o_orderdate` string, `o_orderpriority` string, `o_clerk` string, `o_shippriority` BIGINT ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' LOCATION 's3://
DOC-EXAMPLE-BUCKET
/orders_json';
以下查询可成功运行,与更改数据类型前的原始 SELECT
查询类似:
Select * from orders_json LIMIT 10;