跳转到主要内容
向表中插入数据。 语法
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] [SETTINGS ...] VALUES (v11, v12, v13), (v21, v22, v23), ...
你可以使用 (c1, c2, c3) 指定要插入的列列表。你也可以使用带有列匹配器 (如 *) 和/或修饰符 (如 APPLYEXCEPTREPLACE) 的表达式。 例如,假设有如下表:
SHOW CREATE insert_select_testtable;
CREATE TABLE insert_select_testtable
(
    `a` Int8,
    `b` String,
    `c` Int8
)
ENGINE = MergeTree()
ORDER BY a
INSERT INTO insert_select_testtable (*) VALUES (1, 'a', 1) ;
如果你想将数据插入除列 b 之外的所有列,可以使用 EXCEPT 关键字。结合上面的语法,你需要确保插入的值数量 (VALUES (v11, v13)) 与指定的列数 ((c1, c3)) 一致:
INSERT INTO insert_select_testtable (* EXCEPT(b)) Values (2, 2);
SELECT * FROM insert_select_testtable;
┌─a─┬─b─┬─c─┐
│ 2 │   │ 2 │
└───┴───┴───┘
┌─a─┬─b─┬─c─┐
│ 1 │ a │ 1 │
└───┴───┴───┘
在此示例中,我们可以看到,第二个插入的行中,ac 列使用传入的值填充,b 列则使用默认值填充。也可以使用 DEFAULT 关键字来插入默认值:
INSERT INTO insert_select_testtable VALUES (1, DEFAULT, 1) ;
如果列列表未包含所有现有列,其余列将使用以下内容填充:
  • 根据表定义中指定的 DEFAULT 表达式计算得出的值。
  • 如果未定义 DEFAULT 表达式,则填充为零和空字符串。
数据可以通过 ClickHouse 支持的任意一种 格式 传递给 INSERT。必须在查询中显式指定格式:
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT format_name data_set
例如,以下查询格式与基础形式的 INSERT ... VALUES 完全相同:
INSERT INTO [db.]table [(c1, c2, c3)] FORMAT Values (v11, v12, v13), (v21, v22, v23), ...
ClickHouse 会移除数据前的所有空格,以及一个换行符 (如果存在) 。构造查询时,建议将数据放在查询运算符后的新一行中;如果数据以空格开头,这一点尤其重要。 示例:
INSERT INTO t FORMAT TabSeparated
11  Hello, world!
22  Qwerty
你可以使用命令行客户端HTTP 接口,将数据与查询分开插入。
如果你想为 INSERT 查询指定 SETTINGS,则必须在 FORMAT 子句之前指定,因为 FORMAT format_name 之后的所有内容都会被视为数据。例如:
INSERT INTO table SETTINGS ... FORMAT format_name data_set

约束

如果表定义了约束,系统会检查插入数据中每一行是否满足相应的表达式。如果其中任何一项约束不满足,服务器将引发异常,其中包含约束名称和表达式,并停止该查询。

数据类型验证

ClickHouse 仅在创建表 (CREATE TABLE) 和修改 schema (ALTER TABLE) 时验证允许使用的数据类型 (由 enable_time_time64_typeallow_suspicious_low_cardinality_typesallow_suspicious_fixed_string_types 等设置控制) ,不会在 INSERT 时进行验证。 这意味着,如果某个包含不允许数据类型的表已经存在,那么即使 server 上禁用了相应设置,仍然可以向其中插入数据。这是有意为之——表一旦创建完成,insert 操作就不应被控制类型创建的设置所阻止。 例如:
SET enable_time_time64_type = 1;

CREATE TABLE events
(
    `id` UInt64,
    `event_time` Time
)
ENGINE = MergeTree()
ORDER BY id;

SET enable_time_time64_type = 0;

-- 即使该设置现已禁用,此操作仍然有效。
-- 表已存在,因此插入操作不会被阻止。
INSERT INTO events VALUES (1, '14:30:25');

-- 但使用 Time 类型创建新表将会失败。
CREATE TABLE events_new
(
    `id` UInt64,
    `event_time` Time
)
ENGINE = MergeTree()
ORDER BY id; -- ERR: TYPE_TIME_TIME64_IS_NOT_ENABLED
因此,较新版本的客户端 (其中某项设置默认启用) 可以向较旧版本的服务器 (其中该设置已禁用) 插入包含不允许的数据类型的数据,前提是目标表已具有相应的列类型。校验是在 DDL 层面强制执行的,而不是在 DML 层面。

插入 SELECT 结果

语法
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] SELECT ...
列会根据它们在 SELECT 子句中的位置进行映射。不过,它们在 SELECT 表达式中的名称与 INSERT 目标表中的名称可以不同。如有必要,会执行类型转换。 除 Values 格式外,其他任何数据格式都不允许将值设置为 now()1 + 2 等表达式。Values 格式允许在有限范围内使用表达式,但不建议这样做,因为在这种情况下会使用低效的代码来执行这些表达式。 不支持其他修改数据分区片段的查询:UPDATEDELETEREPLACEMERGEUPSERTINSERT UPDATE。 不过,你可以使用 ALTER TABLE ... DROP PARTITION 删除旧数据。 如果 SELECT 子句包含表函数 input(),则必须在查询末尾指定 FORMAT 子句。 若要向非 Nullable 数据类型的列中插入默认值而不是 NULL,请启用 insert_null_as_default 设置。 INSERT 也支持 CTE (公共表表达式) 。例如,以下两条语句是等价的:
INSERT INTO x WITH y AS (SELECT * FROM numbers(10)) SELECT * FROM y;
WITH y AS (SELECT * FROM numbers(10)) INSERT INTO x SELECT * FROM y;

从文件中插入数据

语法
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] FROM INFILE file_name [COMPRESSION type] [SETTINGS ...] [FORMAT format_name]
使用上述语法可从存储在客户端侧的一个或多个文件中插入数据。file_nametype 是字符串字面量。输入文件的格式必须在 FORMAT 子句中设置。 支持压缩文件。压缩类型会根据文件名扩展名自动识别,也可以在 COMPRESSION 子句中显式指定。支持的类型包括:'none''gzip''deflate''br''xz''zstd''lz4''bz2' 此功能可用于命令行客户端clickhouse-local 示例

使用 FROM INFILE 从单个文件导入数据

使用命令行客户端执行以下查询:
Query
echo 1,A > input.csv ; echo 2,B >> input.csv
clickhouse-client --query="CREATE TABLE table_from_file (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;"
clickhouse-client --query="INSERT INTO table_from_file FROM INFILE 'input.csv' FORMAT CSV;"
clickhouse-client --query="SELECT * FROM table_from_file FORMAT PrettyCompact;"
Response
┌─id─┬─text─┐
│  1 │ A    │
│  2 │ B    │
└────┴──────┘

使用通配符通过 FROM INFILE 处理多个文件

此示例与前一个示例非常相似,但插入操作会通过 FROM INFILE 'input_*.csv' 从多个文件执行。
echo 1,A > input_1.csv ; echo 2,B > input_2.csv
clickhouse-client --query="CREATE TABLE infile_globs (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;"
clickhouse-client --query="INSERT INTO infile_globs FROM INFILE 'input_*.csv' FORMAT CSV;"
clickhouse-client --query="SELECT * FROM infile_globs FORMAT PrettyCompact;"
除了使用 * 选择多个文件外,你还可以使用范围 ({1,2}{1..9}) 以及其他通配符替换规则。以下三种写法都适用于上面的示例:
INSERT INTO infile_globs FROM INFILE 'input_*.csv' FORMAT CSV;
INSERT INTO infile_globs FROM INFILE 'input_{1,2}.csv' FORMAT CSV;
INSERT INTO infile_globs FROM INFILE 'input_?.csv' FORMAT CSV;

使用表函数进行插入

可以向由表函数引用的表中插入数据。 语法
INSERT INTO [TABLE] FUNCTION table_func ...
示例 以下查询使用了 remote 表函数:
Query
CREATE TABLE simple_table (id UInt32, text String) ENGINE=MergeTree() ORDER BY id;
INSERT INTO TABLE FUNCTION remote('localhost', default.simple_table)
    VALUES (100, 'inserted via remote()');
SELECT * FROM simple_table;
Response
┌──id─┬─text──────────────────┐
│ 100 │ inserted via remote() │
└─────┴───────────────────────┘

向 ClickHouse Cloud 插入数据

默认情况下,ClickHouse Cloud 中的服务会提供多个副本,以实现高可用性。当你连接到某个服务时,系统会与其中一个副本建立连接。 INSERT 成功后,数据会写入底层存储。不过,副本接收到这些更新可能需要一些时间。因此,如果你使用另一个连接,在其他副本上执行 SELECT 查询,更新后的数据可能还无法立即反映出来。 可以使用 select_sequential_consistency 强制副本接收最新更新。以下是一个使用此设置的 SELECT 查询示例:
SELECT .... SETTINGS select_sequential_consistency = 1;
请注意,使用 select_sequential_consistency 会增加 ClickHouse Keeper (ClickHouse Cloud 在内部使用的协调服务) 的负载,并且可能会因该服务的负载情况而导致性能下降。除非确有必要,我们不建议启用此设置。推荐的做法是在同一 session 中执行读写操作,或使用采用 native protocol 的客户端驱动 (因此支持粘性连接) 。

在复制环境中插入数据

在复制环境中,数据完成复制后,才会在其他副本上可见。执行 INSERT 后,数据会立即开始复制 (即下载到其他副本) 。这与 ClickHouse Cloud 不同:在 ClickHouse Cloud 中,数据会立即写入共享存储,副本则通过订阅元数据变更进行同步。 请注意,在复制环境中,INSERTs 有时可能耗时较长 (大约为 1 秒) ,因为这需要提交到 ClickHouse Keeper 以达成分布式共识。使用 S3 作为存储也会带来额外延迟。

性能注意事项

INSERT 会按主键对输入数据排序,并按分区键将其拆分到不同分区中。如果一次将数据插入多个分区,INSERT 查询的性能可能会明显下降。为避免这种情况:
  • 以较大的批次写入数据,例如每次 100,000 行。
  • 在将数据上传到 ClickHouse 之前,先按分区键对数据分组。
在以下情况下,性能通常不会下降:
  • 实时写入数据。
  • 上传通常按时间排序的数据。

异步插入

对于小而频繁的插入操作,可以采用异步插入的方式。此类插入的数据会先合并为批次,然后再安全地写入表中。要使用异步插入,请启用 async_insert 设置。 使用 async_insertBuffer 表引擎 都会带来额外的缓冲。

大规模或耗时较长的插入

当插入大量数据时,ClickHouse 会通过称为“squashing”的过程来优化写入性能。内存中较小的已插入数据块会先合并并压缩成更大的块,然后再写入磁盘。squashing 可减少每次写入操作的相关开销。在此过程中,ClickHouse 每完成写入 max_insert_block_size 行后,这部分已插入的数据就可以被查询到。 另请参见
最后修改于 2026年6月10日