INSERT INTO 语句
将数据插入到表中。
语法
INSERT INTO [TABLE] [db.]table [(c1, c2, c3)] [SETTINGS ...] VALUES (v11, v12, v13), (v21, v22, v23), ...
您可以使用 (c1, c2, c3)
指定要插入的列列表。您还可以将表达式与列匹配符(如 *
)和/或修饰符(如APPLY、EXCEPT、REPLACE)一起使用。
例如,考虑下表
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 │
└───┴───┴───┘
在此示例中,我们看到第二个插入的行使用传递的值填充了 a
和 c
列,而 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 格式允许有限地使用表达式,但不建议这样做,因为在这种情况下,低效的代码用于执行它们。
不支持其他用于修改数据部分的查询:UPDATE
、DELETE
、REPLACE
、MERGE
、UPSERT
、INSERT UPDATE
。但是,您可以使用 ALTER TABLE ... DROP PARTITION
删除旧数据。
如果 SELECT
子句包含表函数 input(),则必须在查询末尾指定 FORMAT
子句。
要将默认值而不是 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_name
和 type
是字符串字面量。输入文件格式必须在 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 │
└────┴──────┘
使用 globs 的 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 ...
示例
remote 表函数在以下查询中使用
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_insert
或 Buffer
表引擎 会导致额外的缓冲。
大型或长时间运行的插入
当您插入大量数据时,ClickHouse 将通过称为“压缩”的过程优化写入性能。内存中插入的小数据块在写入磁盘之前被合并和压缩成更大的块。压缩减少了与每个写入操作相关的开销。在此过程中,在 ClickHouse 完成写入每个max_insert_block_size
行后,插入的数据将可用于查询。
另请参阅