跳到主要内容
跳到主要内容

S3 表引擎

该引擎提供与 Amazon S3 生态系统的集成。该引擎与 HDFS 引擎相似,但提供特定于 S3 的功能。

示例

CREATE TABLE s3_engine_table (name String, value UInt32)
    ENGINE=S3('https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/test-data.csv.gz', 'CSV', 'gzip')
    SETTINGS input_format_with_names_use_header = 0;

INSERT INTO s3_engine_table VALUES ('one', 1), ('two', 2), ('three', 3);

SELECT * FROM s3_engine_table LIMIT 2;
┌─name─┬─value─┐
│ one  │     1 │
│ two  │     2 │
└──────┴───────┘

创建表

CREATE TABLE s3_engine_table (name String, value UInt32)
    ENGINE = S3(path [, NOSIGN | aws_access_key_id, aws_secret_access_key,] format, [compression], [partition_strategy], [partition_columns_in_data_file])
    [PARTITION BY expr]
    [SETTINGS ...]

引擎参数

  • path — 包含文件路径的存储桶 URL。支持只读模式下的以下通配符:***?{abc,def}{N..M},其中 NM 为数字,'abc''def' 为字符串。有关更多信息,请见 下文
  • NOSIGN - 如果在凭证位置提供此关键字,则所有请求将不被签名。
  • format — 文件的 格式
  • aws_access_key_idaws_secret_access_key - 用于 AWS 帐户用户的长期凭据。您可以将其用于身份验证请求。该参数是可选的。如果未指定凭据,则将使用配置文件中的凭据。有关更多信息,请参见 使用 S3 存储数据
  • compression — 压缩类型。支持的值:nonegzip/gzbrotli/brxz/LZMAzstd/zst。该参数为可选项。默认情况下,它将根据文件扩展名自动检测压缩。
  • partition_strategy – 选项:WILDCARDHIVEWILDCARD 需要在路径中包含 {_partition_id},并替换为分区键。HIVE 不允许使用通配符,假定路径为表的根,并生成带有 Snowflake ID 作为文件名并以文件格式作为扩展名的 Hive 风格分区目录。默认为 WILDCARD
  • partition_columns_in_data_file - 仅在使用 HIVE 分区策略时使用。告知 ClickHouse 是否期望分区列写入数据文件中。默认为 false
  • storage_class_name - 选项:STANDARDINTELLIGENT_TIERING,允许指定 AWS S3 Intelligent Tiering

数据缓存

S3 表引擎支持在本地磁盘上进行数据缓存。 请参阅此 部分 中的文件系统缓存配置选项和用法。 缓存是根据路径和存储对象的 ETag 进行的,因此 ClickHouse 不会读取过期版本的缓存。

要启用缓存,请使用设置 filesystem_cache_name = '<name>'enable_filesystem_cache = 1

SELECT *
FROM s3('http://minio:10000/clickhouse//test_3.csv', 'minioadmin', 'minioadminpassword', 'CSV')
SETTINGS filesystem_cache_name = 'cache_for_s3', enable_filesystem_cache = 1;

有两种方法可以在配置文件中定义缓存。

  1. 将以下部分添加到 ClickHouse 配置文件中:
<clickhouse>
    <filesystem_caches>
        <cache_for_s3>
            <path>path to cache directory</path>
            <max_size>10Gi</max_size>
        </cache_for_s3>
    </filesystem_caches>
</clickhouse>
  1. 重用来自 ClickHouse storage_configuration 部分的缓存配置(因此缓存存储),在此描述

按分区

PARTITION BY — 可选。在大多数情况下,您不需要分区键,如果需要,通常不需要比按月更细粒度的分区。分区不会加快查询速度(与 ORDER BY 表达式相反)。您永远不应该使用过于细粒度的分区。不要按客户标识符或名称对数据进行分区(相反,请将客户标识符或名称作为 ORDER BY 表达式中的第一列)。

按月分区时,请使用 toYYYYMM(date_column) 表达式,其中 date_column 是类型为 Date 的日期列。这里的分区名称采用 "YYYYMM" 格式。

分区策略

WILDCARD(默认):将文件路径中的 {_partition_id} 通配符替换为实际分区键。不支持读取。

HIVE 实现 Hive 风格的分区以进行读写。读取是通过递归的 glob 模式实现的,相当于 SELECT * FROM s3('table_root/**.parquet')。 写入生成的文件格式为: <prefix>/<key1=val1/key2=val2...>/<snowflakeid>.<toLower(file_format)>

注意:使用 HIVE 分区策略时,use_hive_partitioning 设置无效。

HIVE 分区策略的示例:

arthur :) CREATE TABLE t_03363_parquet (year UInt16, country String, counter UInt8)
ENGINE = S3(s3_conn, filename = 't_03363_parquet', format = Parquet, partition_strategy='hive')
PARTITION BY (year, country);

arthur :) INSERT INTO t_03363_parquet VALUES
    (2022, 'USA', 1),
    (2022, 'Canada', 2),
    (2023, 'USA', 3),
    (2023, 'Mexico', 4),
    (2024, 'France', 5),
    (2024, 'Germany', 6),
    (2024, 'Germany', 7),
    (1999, 'Brazil', 8),
    (2100, 'Japan', 9),
    (2024, 'CN', 10),
    (2025, '', 11);

arthur :) select _path, * from t_03363_parquet;

    ┌─_path──────────────────────────────────────────────────────────────────────┬─year─┬─country─┬─counter─┐
 1. │ test/t_03363_parquet/year=2100/country=Japan/7329604473272971264.parquet   │ 2100 │ Japan   │       9 │
 2. │ test/t_03363_parquet/year=2024/country=France/7329604473323302912.parquet  │ 2024 │ France  │       5 │
 3. │ test/t_03363_parquet/year=2022/country=Canada/7329604473314914304.parquet  │ 2022 │ Canada  │       2 │
 4. │ test/t_03363_parquet/year=1999/country=Brazil/7329604473289748480.parquet  │ 1999 │ Brazil  │       8 │
 5. │ test/t_03363_parquet/year=2023/country=Mexico/7329604473293942784.parquet  │ 2023 │ Mexico  │       4 │
 6. │ test/t_03363_parquet/year=2023/country=USA/7329604473319108608.parquet     │ 2023 │ USA     │       3 │
 7. │ test/t_03363_parquet/year=2025/country=/7329604473327497216.parquet        │ 2025 │         │      11 │
 8. │ test/t_03363_parquet/year=2024/country=CN/7329604473310720000.parquet      │ 2024 │ CN      │      10 │
 9. │ test/t_03363_parquet/year=2022/country=USA/7329604473298137088.parquet     │ 2022 │ USA     │       1 │
10. │ test/t_03363_parquet/year=2024/country=Germany/7329604473306525696.parquet │ 2024 │ Germany │       6 │
11. │ test/t_03363_parquet/year=2024/country=Germany/7329604473306525696.parquet │ 2024 │ Germany │       7 │
    └────────────────────────────────────────────────────────────────────────────┴──────┴─────────┴─────────┘

查询分区数据

该示例使用 docker compose 配方,集成了 ClickHouse 和 MinIO。您应该能够通过替换端点和身份验证值来重现相同的查询。

请注意,ENGINE 配置中的 S3 端点使用了参数令牌 {_partition_id} 作为 S3 对象(文件名)的一部分,并且 SELECT 查询针对这些生成的对象名称(例如 test_3.csv)进行选择。

备注

如示例所示,目前不直接支持从分区的 S3 表进行查询,但可以使用 S3 表函数查询各个分区来实现。

写入分区数据到 S3 的主要用例是将数据转移到另一个 ClickHouse 系统(例如,从本地系统迁移到 ClickHouse Cloud)。因为 ClickHouse 数据集通常非常大,并且网络可靠性有时不完美,所以分批传输数据集是有意义的,因此进行了分区写入。

创建表

CREATE TABLE p
(
    `column1` UInt32,
    `column2` UInt32,
    `column3` UInt32
)
ENGINE = S3(
-- highlight-next-line
           'http://minio:10000/clickhouse//test_{_partition_id}.csv',
           'minioadmin',
           'minioadminpassword',
           'CSV')
PARTITION BY column3

插入数据

INSERT INTO p VALUES (1, 2, 3), (3, 2, 1), (78, 43, 45)

从分区 3 选择

提示

此查询使用 S3 表函数

SELECT *
FROM s3('http://minio:10000/clickhouse//test_3.csv', 'minioadmin', 'minioadminpassword', 'CSV')
┌─c1─┬─c2─┬─c3─┐
│  1 │  2 │  3 │
└────┴────┴────┘

从分区 1 选择

SELECT *
FROM s3('http://minio:10000/clickhouse//test_1.csv', 'minioadmin', 'minioadminpassword', 'CSV')
┌─c1─┬─c2─┬─c3─┐
│  3 │  2 │  1 │
└────┴────┴────┘

从分区 45 选择

SELECT *
FROM s3('http://minio:10000/clickhouse//test_45.csv', 'minioadmin', 'minioadminpassword', 'CSV')
┌─c1─┬─c2─┬─c3─┐
│ 78 │ 43 │ 45 │
└────┴────┴────┘

限制

您自然可能尝试 Select * from p,但如上所述,此查询将失败;请使用前面的查询。

SELECT * FROM p
Received exception from server (version 23.4.1):
Code: 48. DB::Exception: Received from localhost:9000. DB::Exception: Reading from a partitioned S3 storage is not implemented yet. (NOT_IMPLEMENTED)

插入数据

请注意,行只能插入到新文件中。没有合并周期或文件拆分操作。一旦写入文件,后续插入将失败。为避免此问题,您可以使用 s3_truncate_on_inserts3_create_new_file_on_insert 设置。详细信息请参见 此处

虚拟列

  • _path — 文件路径。类型:LowCardinality(String)
  • _file — 文件名。类型:LowCardinality(String)
  • _size — 文件大小(以字节为单位)。类型:Nullable(UInt64)。如果大小未知,值为 NULL
  • _time — 文件最后修改时间。类型:Nullable(DateTime)。如果时间未知,值为 NULL
  • _etag — 文件的 ETag。类型:LowCardinality(String)。如果 ETag 未知,值为 NULL

有关虚拟列的更多信息,请参见 这里

实现细节

  • 读取和写入可以并行进行。

  • 不支持:

    • ALTERSELECT...SAMPLE 操作。
    • 索引。
    • 零拷贝 复制是可能的,但不受支持。
    零拷贝复制尚未准备好用于生产

    ClickHouse 版本 22.8 及更高版本中默认禁用零拷贝复制。此功能不建议用于生产环境。

路径中的通配符

path 参数可以使用类似 bash 的通配符指定多个文件。要进行处理,文件应存在并与整个路径模式匹配。文件列表在 SELECT 时确定(而不是在 CREATE 时)。

  • * — 替代任何数量的任何字符,除了 /,包括空字符串。
  • ** — 替代任何数量的任何字符,包括 /,也包括空字符串。
  • ? — 替代任何单个字符。
  • {some_string,another_string,yet_another_one} — 替代任一字符串 'some_string', 'another_string', 'yet_another_one'
  • {N..M} — 替代范围内的任意数字,包括 N 和 M 两个边界。N 和 M 可以有前导零,例如 000..078

带有 {} 的结构与 remote 表函数相似。

备注

如果文件列表包含带前导零的数字范围,请分别为每个数字使用带大括号的结构,或使用 ?

带通配符的示例 1

创建文件命名为 file-000.csvfile-001.csv,...,file-999.csv 的表:

CREATE TABLE big_table (name String, value UInt32)
    ENGINE = S3('https://clickhouse-public-datasets.s3.amazonaws.com/my-bucket/my_folder/file-{000..999}.csv', 'CSV');

带通配符的示例 2

假设我们在 S3 上有几个 CSV 格式的文件,其 URI 如下:

有几种方法可以创建一个包含所有六个文件的表:

  1. 指定文件后缀的范围:
CREATE TABLE table_with_range (name String, value UInt32)
    ENGINE = S3('https://clickhouse-public-datasets.s3.amazonaws.com/my-bucket/{some,another}_folder/some_file_{1..3}', 'CSV');
  1. 获取所有以 some_file_ 为前缀的文件(两个文件夹中不应有其他具有该前缀的额外文件):
CREATE TABLE table_with_question_mark (name String, value UInt32)
    ENGINE = S3('https://clickhouse-public-datasets.s3.amazonaws.com/my-bucket/{some,another}_folder/some_file_?', 'CSV');
  1. 获取两个文件夹中的所有文件(所有文件应满足查询中描述的格式和模式):
CREATE TABLE table_with_asterisk (name String, value UInt32)
    ENGINE = S3('https://clickhouse-public-datasets.s3.amazonaws.com/my-bucket/{some,another}_folder/*', 'CSV');

存储设置

S3 相关设置

以下设置可以在查询执行之前设置或放置在配置文件中。

  • s3_max_single_part_upload_size — 使用单个上传到 S3 的对象的最大大小。默认值为 32Mb
  • s3_min_upload_part_size — 在 S3 多部分上传 中上传部分的最小大小。默认值为 16Mb
  • s3_max_redirects — 允许的最大 S3 重定向跳数。默认值为 10
  • s3_single_read_retries — 单次读取的最大尝试次数。默认值为 4
  • s3_max_put_rps — 在限制之前的最大 PUT 请求每秒速率。默认值为 0(无限制)。
  • s3_max_put_burst — 在达到每秒请求限制之前,可以同时发起的最大请求数量。默认为 0(与 s3_max_put_rps 相等)。
  • s3_max_get_rps — 在限制之前的最大 GET 请求每秒速率。默认值为 0(无限制)。
  • s3_max_get_burst — 在达到每秒请求限制之前,可以同时发起的最大请求数量。默认为 0(与 s3_max_get_rps 相等)。
  • s3_upload_part_size_multiply_factor - 在从单次写入到 S3 上传的 s3_multiply_parts_count_threshold 部分每次乘以此因子。默认值为 2
  • s3_upload_part_size_multiply_parts_count_threshold - 每次上传到 S3 的此数量的部分,s3_min_upload_part_size 乘以 s3_upload_part_size_multiply_factor。默认值为 500
  • s3_max_inflight_parts_for_one_file - 限制一次性可以并行运行的 PUT 请求数量。该数量应受到限制。值为 0 表示无限制。默认值为 20。每个在途部分的缓冲区大小为 s3_min_upload_part_size,前 s3_upload_part_size_multiply_factor 个部分适用,文件较大时则更多,见 upload_part_size_multiply_factor。使用默认设置时,一个上传的文件在小于 8G 的情况下最多消耗 320Mb。较大文件的消耗则更大。

安全考虑:如果恶意用户可以指定任意 S3 URL,则 s3_max_redirects 必须设置为零,以避免 SSRF 攻击;或者在服务器配置中另行指定 remote_host_filter

基于端点的设置

以下设置可以在配置文件中为给定的端点指定(将通过 URL 的精确前缀进行匹配):

  • endpoint — 指定端点的前缀。必填。
  • access_key_idsecret_access_key — 指定给定端点可用的凭据。可选。
  • use_environment_credentials — 如果设置为 true,S3 客户端将尝试从环境变量和 Amazon EC2 元数据中获取凭据。可选,默认值为 false
  • region — 指定 S3 区域名称。可选。
  • use_insecure_imds_request — 如果设置为 true,S3 客户端在从 Amazon EC2 元数据中获取凭据时将使用不安全的 IMDS 请求。可选,默认值为 false
  • expiration_window_seconds — 检查以过期为基础的凭据是否已过期的宽限期。可选,默认值为 120
  • no_sign_request - 忽略所有凭据,因此请求不被签名。适用于访问公共存储桶。
  • header — 在请求添加指定的 HTTP 头到给定的端点。可选,可以多次指定。
  • access_header - 在请求添加指定的 HTTP 头到给定的端点,当没有其他来源的凭据时。
  • server_side_encryption_customer_key_base64 — 如果指定,则将设置访问 S3 对象所需的 SSE-C 加密所需的头。可选。
  • server_side_encryption_kms_key_id - 如果指定,则将设置访问 S3 对象所需的 SSE-KMS 加密 所需的头。如果指定空字符串,则将使用 AWS 管理的 S3 密钥。可选。
  • server_side_encryption_kms_encryption_context - 如果与 server_side_encryption_kms_key_id 一起指定,则将设置 SSE-KMS 的给定加密上下文头。可选。
  • server_side_encryption_kms_bucket_key_enabled - 如果与 server_side_encryption_kms_key_id 一起指定,则将设置启用 SSE-KMS 的 S3 存储桶密钥的头。可选,可以为 truefalse,默认为无(匹配存储桶级别的设置)。
  • max_single_read_retries — 单次读取的最大尝试次数。默认值为 4。可选。
  • max_put_rpsmax_put_burstmax_get_rpsmax_get_burst - 用于特定端点而不是每个查询的节流设置(见上文描述)。可选。

示例:

<s3>
    <endpoint-name>
        <endpoint>https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/</endpoint>
        <!-- <access_key_id>ACCESS_KEY_ID</access_key_id> -->
        <!-- <secret_access_key>SECRET_ACCESS_KEY</secret_access_key> -->
        <!-- <region>us-west-1</region> -->
        <!-- <use_environment_credentials>false</use_environment_credentials> -->
        <!-- <use_insecure_imds_request>false</use_insecure_imds_request> -->
        <!-- <expiration_window_seconds>120</expiration_window_seconds> -->
        <!-- <no_sign_request>false</no_sign_request> -->
        <!-- <header>Authorization: Bearer SOME-TOKEN</header> -->
        <!-- <server_side_encryption_customer_key_base64>BASE64-ENCODED-KEY</server_side_encryption_customer_key_base64> -->
        <!-- <server_side_encryption_kms_key_id>KMS_KEY_ID</server_side_encryption_kms_key_id> -->
        <!-- <server_side_encryption_kms_encryption_context>KMS_ENCRYPTION_CONTEXT</server_side_encryption_kms_encryption_context> -->
        <!-- <server_side_encryption_kms_bucket_key_enabled>true</server_side_encryption_kms_bucket_key_enabled> -->
        <!-- <max_single_read_retries>4</max_single_read_retries> -->
    </endpoint-name>
</s3>

处理档案

假设我们在 S3 上有几个档案文件,其 URI 如下:

使用 :: 提取这些档案中的数据是可能的。Globs 可以在 URL 部分以及 :: 后的部分(负责档案内文件的名称)使用。

SELECT *
FROM s3(
   'https://s3-us-west-1.amazonaws.com/umbrella-static/top-1m-2018-01-1{0..2}.csv.zip :: *.csv'
);
备注

ClickHouse 支持三种档案格式: ZIP TAR 7Z 虽然 ZIP 和 TAR 档案可以从任何支持的存储位置访问,但 7Z 档案只能从安装 ClickHouse 的本地文件系统读取。

访问公共存储桶

ClickHouse 尝试从许多不同类型的来源获取凭据。 有时,访问某些公共存储桶时可能会出现问题,导致客户端返回 403 错误代码。 通过使用 NOSIGN 关键字,可以避免此问题,从而强制客户端忽略所有凭据,并且不签署请求。

CREATE TABLE big_table (name String, value UInt32)
    ENGINE = S3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/aapl_stock.csv', NOSIGN, 'CSVWithNames');

优化性能

有关优化 S3 功能性能的详细信息,请参见 我们的详细指南

另请参阅