跳至主要内容

INSERT INTO 语句

将数据插入表中。

语法

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' 之外的所有列,则需要传递与括号中选择的列数量一样多的值,然后

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

约束

如果表具有 约束,则会检查插入数据的每一行的表达式。如果这些约束中的任何一个不满足 - 服务器将引发一个包含约束名称和表达式的异常,查询将停止。

插入 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 子句。

要在具有非空数据类型的列中插入默认值而不是 NULL,请启用 insert_null_as_default 设置。

从文件插入数据

语法

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 的单个文件

使用 命令行客户端 执行以下查询

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;"

结果

┌─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})和其他 glob 替换。这三个都适用于上述示例。

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 ...

示例

远程 表函数用于以下查询

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;

结果

┌──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 在内部使用)的负载,并且可能会导致性能下降,具体取决于服务的负载。除非必要,否则我们建议不要启用此设置。建议的方法是在同一会话中执行读/写操作,或使用支持本机协议(因此支持粘性连接)的客户端驱动程序。

插入复制设置

在复制设置中,数据在复制后将在其他副本上可见。数据在 INSERT 后立即开始复制(下载到其他副本)。这与 ClickHouse Cloud 不同,在 ClickHouse Cloud 中,数据会立即写入共享存储,副本会订阅元数据更改。

请注意,对于复制设置,INSERT 有时可能需要相当长的时间(大约一秒钟),因为它需要提交到 ClickHouse Keeper 以进行分布式共识。使用 S3 进行存储也会增加额外的延迟。

性能注意事项

INSERT 会根据主键对输入数据进行排序,并根据分区键将其拆分为分区。如果您一次将数据插入多个分区,则会大大降低 INSERT 查询的性能。为了避免这种情况

  • 一次添加相当大的批次数据,例如每次 100,000 行。
  • 在将数据上传到 ClickHouse 之前,按分区键对数据进行分组。

如果性能不会下降

  • 实时添加数据。
  • 您上传通常按时间排序的数据。

异步插入

可以在少量但频繁的插入中异步插入数据。来自此类插入的数据将组合成批次,然后安全地插入表中。要使用异步插入,请启用 async_insert 设置。

使用 async_insertBuffer 表引擎 会导致额外的缓冲。

大批量或长时间插入数据

当您插入大量数据时,ClickHouse 会通过一个称为“压缩”的过程来优化写入性能。内存中插入的小数据块会在写入磁盘之前合并并压缩成更大的数据块。压缩减少了每个写入操作相关的开销。在此过程中,在 ClickHouse 完成写入每个max_insert_block_size 行后,插入的数据即可供查询。

另请参阅