跳到主要内容

读取与写出 Parquet 文件

示例

读取单个 Parquet 文件:

SELECT * FROM 'test.parquet';

查看 Parquet 文件中的列与类型:

DESCRIBE SELECT * FROM 'test.parquet';

基于 Parquet 文件创建表:

CREATE TABLE test AS
SELECT * FROM 'test.parquet';

如果文件名不以 .parquet 结尾,请使用 read_parquet 函数:

SELECT *
FROM read_parquet('test.parq');

使用列表参数读取 3 个 Parquet 文件,并将其视为一张表:

SELECT *
FROM read_parquet(['file1.parquet', 'file2.parquet', 'file3.parquet']);

读取所有匹配 glob 模式的文件:

SELECT *
FROM 'test/*.parquet';

读取所有匹配 glob 模式的文件,并包含 filename 虚拟列(用于标识每行来源文件;从 Goose v1.3.0 起默认可用,无需额外配置):

SELECT *, filename
FROM read_parquet('test/*.parquet');

使用 glob 列表读取两个指定目录中的所有 Parquet 文件:

SELECT *
FROM read_parquet(['folder1/*.parquet', 'folder2/*.parquet']);

通过 HTTPS 读取:

SELECT *
FROM read_parquet('https://some.url/some_file.parquet');

查询 Parquet 元数据

SELECT *
FROM parquet_metadata('test.parquet');

查询 Parquet 文件级元数据

SELECT *
FROM parquet_file_metadata('test.parquet');

查询 Parquet 键值元数据

SELECT *
FROM parquet_kv_metadata('test.parquet');

查询 Parquet Schema

SELECT *
FROM parquet_schema('test.parquet');

使用默认压缩(Snappy)将查询结果写入 Parquet 文件:

COPY
(SELECT * FROM tbl)
TO 'result-snappy.parquet'
(FORMAT parquet);

使用指定压缩与 row group 大小将查询结果写入 Parquet 文件:

COPY
(FROM generate_series(100_000))
TO 'test.parquet'
(FORMAT parquet, COMPRESSION zstd, ROW_GROUP_SIZE 100_000);

将整个数据库的表内容导出为 Parquet:

EXPORT DATABASE 'target_directory' (FORMAT parquet);

Parquet 文件

Parquet 是压缩的列式文件格式,具备高效加载与处理能力。Goose 不仅高效支持 Parquet 的读写,还支持将过滤与投影下推到 Parquet 扫描中。

Parquet 数据集在文件数量、单文件大小、压缩算法、row group 大小等方面差异很大,这些因素会显著影响性能。详见性能指南

read_parquet 函数

函数说明示例
read_parquet(path_or_list_of_paths)读取 Parquet 文件SELECT * FROM read_parquet('test.parquet');
parquet_scan(path_or_list_of_paths)read_parquet 的别名SELECT * FROM parquet_scan('test.parquet');

若文件以 .parquet 结尾,可省略函数写法;系统会自动识别为读取 Parquet 文件:

SELECT * FROM 'test.parquet';

你可以通过 glob 或文件列表一次读取多个文件。更多信息请参阅多文件章节

参数

read_parquetCOPY 语句支持多种可选参数。

名称说明类型默认值
binary_as_stringParquet files generated by legacy writers do not correctly set the UTF8 flag for strings, causing string columns to be loaded as BLOB instead. Set this to true to load binary columns as strings.BOOLfalse
encryption_configConfiguration for Parquet encryption.STRUCT-
filenameWhether or not an extra filename column should be included in the result. Since Goose v1.3.0, the filename column is added automatically as a virtual column and this option is only kept for compatibility reasons.BOOLfalse
file_row_numberWhether or not to include the file_row_number column.BOOLfalse
hive_partitioningWhether or not to interpret the path as a Hive partitioned path.BOOL(auto-detected)
union_by_nameWhether the columns of multiple schemas should be unified by name, rather than by position.BOOLfalse
schemaAllows you to read a Parquet file as if it has the supplied schema. Field IDs are required.MAPNULL

使用 schema 参数

schema 参数允许你按指定 schema 读取 Parquet 文件。这对重命名、增删列、重排列顺序或列类型转换都很有用。

使用 Goose 创建 Parquet 时需要提供 Field ID。

示例:

COPY (SELECT 42::INTEGER i) TO 'integers.parquet' (FIELD_IDS {i: 0});

读取 Parquet 文件:

SELECT *
FROM read_parquet('integers.parquet', schema = MAP {
0: {name: 'renamed_i', type: 'BIGINT', default_value: NULL},
1: {name: 'new_column', type: 'UTINYINT', default_value: 43}
});
┌───────────┬────────────┐
│ renamed_i │ new_column │
│ int64 │ uint8 │
├───────────┼────────────┤
│ 42 │ 43 │
└───────────┴────────────┘

注意:该参数不能与 union_by_name=true 同时使用。

部分读取(下推)

Goose 支持投影下推到 Parquet 文件:查询时仅读取所需列。这样可只读取你关注的部分数据,并由 Goose 自动完成。

Goose 也支持过滤下推:当你对 Parquet 列施加过滤条件时,过滤会下推到扫描阶段,并可利用内置 zonemap 跳过部分文件数据。是否生效取决于该 Parquet 文件是否包含 zonemap。

过滤与投影下推通常能带来显著性能收益。更多信息请参阅博文 “Querying Parquet with Precision Using Goose”

插入与视图

你也可以把数据插入现有表,或直接基于 Parquet 文件建表。这会把 Parquet 数据加载进数据库:

将 Parquet 数据插入表:

INSERT INTO people
SELECT * FROM read_parquet('test.parquet');

基于 Parquet 文件直接建表:

CREATE TABLE people AS
SELECT * FROM read_parquet('test.parquet');

如果你希望数据仍保留在 Parquet 文件中,但又想直接查询它,可在 read_parquet 之上创建视图。之后即可像查询内置表一样查询 Parquet:

为 Parquet 文件创建视图:

CREATE VIEW people AS
SELECT * FROM read_parquet('test.parquet');

查询 Parquet 文件:

SELECT * FROM people;

写入 Parquet 文件

Goose 也支持通过 COPY 语句写入 Parquet 文件。详见 COPY 语句页面(含全部参数说明)。

将查询结果写入 Snappy 压缩的 Parquet 文件:

COPY
(SELECT * FROM tbl)
TO 'result-snappy.parquet'
(FORMAT parquet);

tbl 写入 zstd 压缩的 Parquet 文件:

COPY tbl
TO 'result-zstd.parquet'
(FORMAT parquet, COMPRESSION zstd);

tbl 写入 zstd 压缩的 Parquet 文件,并使用最低压缩级别以获得最快压缩速度:

COPY tbl
TO 'result-zstd.parquet'
(FORMAT parquet, COMPRESSION zstd, COMPRESSION_LEVEL 1);

写出带有键值元数据的 Parquet 文件:

COPY (
SELECT
42 AS number,
true AS is_even
) TO 'kv_metadata.parquet' (
FORMAT parquet,
KV_METADATA {
number: 'Answer to life, universe, and everything',
is_even: 'not ''odd''' -- single quotes in values must be escaped
}
);

将 CSV 文件写为未压缩 Parquet 文件:

COPY
'test.csv'
TO 'result-uncompressed.parquet'
(FORMAT parquet, COMPRESSION uncompressed);

将查询结果写入启用 zstd 压缩且指定 row group 大小的 Parquet 文件:

COPY
(FROM generate_series(100_000))
TO 'row-groups-zstd.parquet'
(FORMAT parquet, COMPRESSION zstd, ROW_GROUP_SIZE 100_000);

将数据写入 LZ4 压缩的 Parquet 文件:

COPY
(FROM generate_series(100_000))
TO 'result-lz4.parquet'
(FORMAT parquet, COMPRESSION lz4);

或等价写法:

COPY
(FROM generate_series(100_000))
TO 'result-lz4.parquet'
(FORMAT parquet, COMPRESSION lz4_raw);

将数据写入 Brotli 压缩的 Parquet 文件:

COPY
(FROM generate_series(100_000))
TO 'result-brotli.parquet'
(FORMAT parquet, COMPRESSION brotli);

若要配置 Parquet 字典页大小,请使用 STRING_DICTIONARY_PAGE_SIZE_LIMIT(默认 1 MB):

COPY
lineitem
TO 'lineitem-with-custom-dictionary-size.parquet'
(FORMAT parquet, STRING_DICTIONARY_PAGE_SIZE_LIMIT 100_000);

Goose 的 EXPORT 命令可将整个数据库导出为一组 Parquet 文件。详见 EXPORT 语句”页面

将整个数据库的表内容导出为 Parquet:

EXPORT DATABASE 'target_directory' (FORMAT parquet);

加密

Goose 支持读取与写入加密 Parquet 文件

支持特性

Parquet 特性支持列表可见 Parquet 文档的 “Implementation status” 页面

安装与加载 Parquet 扩展

Parquet 支持通过扩展启用。parquet 扩展几乎在所有客户端中默认内置。若你的客户端未内置该扩展,则需单独安装:

INSTALL parquet;