跳至主要内容

插入数据

基本示例

您可以使用熟悉的 INSERT INTO TABLE 命令与 ClickHouse

INSERT INTO helloworld.my_first_table (user_id, message, timestamp, metric) VALUES
(101, 'Hello, ClickHouse!', now(), -1.0 ),
(102, 'Insert a lot of rows per batch', yesterday(), 1.41421 ),
(102, 'Sort your data based on your commonly-used queries', today(), 2.718 ),
(101, 'Granules are the smallest chunks of data read', now() + 5, 3.14159 )

让我们验证它是否有效 - 您应该看到插入的四行数据

SELECT * FROM helloworld.my_first_table

将数据插入 ClickHouse 与 OLTP 数据库

作为 OLAP 数据库,ClickHouse 针对高性能和可扩展性进行了优化,允许每秒插入数百万行数据。这是通过高度并行化的架构、列式存储的高压缩率实现的,但也以一致性为代价。更具体地说,ClickHouse 针对追加操作进行了优化,并且仅提供最终一致性保证。

相比之下,OLTP 数据库(如 Postgres)专门针对具有完整 ACID 兼容性的事务插入进行了优化,确保了强一致性和可靠性保证。PostgreSQL 使用 MVCC(多版本并发控制)来处理并发事务,这涉及维护多个数据版本。这些事务每次可能只包含少量行,并且由于可靠性保证限制了插入性能,因此会产生相当大的开销。

为了在获得强一致性保证的同时实现高插入性能,用户在将数据插入 ClickHouse 时应遵守以下简单规则。这也有助于避免用户首次使用 ClickHouse 并复制其 OLTP 插入策略时遇到的常见问题。

插入的最佳实践

  • 使用较大的批次大小 - 默认情况下,发送到 ClickHouse 的每个插入操作都会导致 ClickHouse 立即创建存储的一部分,其中包含插入数据以及需要存储的其他元数据。因此,与发送大量包含较少数据的插入操作相比,发送少量包含更多数据的插入操作将减少所需的写入次数。通常,我们建议一次至少以 1,000 行的相当大的批次插入数据,理想情况下在 10,000 到 100,000 行之间。更多详细信息此处。如果无法使用大批次,请使用下面描述的异步插入。

  • 确保一致的批次以进行幂等重试 - 默认情况下,如果相同,则插入 ClickHouse 的操作是同步的且幂等的。对于 MergeTree 引擎系列的表,ClickHouse 默认会自动对插入进行去重。这意味着在以下情况下,插入操作是可以容忍的

    1. 如果接收数据的节点出现问题,插入查询将超时(或收到更具体的错误)并且不会收到确认。

    2. 如果数据已由节点写入,但由于网络中断无法将确认返回到查询的发送方,则发送方将收到超时或网络错误。

      从客户端的角度来看,(i) 和 (ii) 可能难以区分。但是,在这两种情况下,未确认的插入都可以立即重试。只要重试的插入查询包含相同顺序的相同数据,ClickHouse 就会自动忽略重试的插入(如果未确认的原始插入成功)。

  • 插入到 MergeTree 表或 Distributed 表 - 我们建议直接插入到 MergeTree(或 Replicated 表)中,如果数据已分片,则在节点集中平衡请求,并使用 internal_replication=true。这将使 ClickHouse 将数据复制到任何副本分片并确保数据最终一致。如果这种客户端负载平衡不方便,用户可以通过Distributed 表进行插入。然后,这将跨节点分发写入(同样,请保留 internal_replication=true)。这种方法的性能略低,因为写入必须在具有 Distributed 表的节点上本地执行,然后发送到分片。

  • 对于小批次,使用异步插入 - 在某些情况下,客户端批处理不可行,例如,具有数百或数千个用于发送日志、指标、跟踪等的单一用途代理的可观察性用例,其中实时传输这些数据对于尽快检测问题和异常至关重要。此外,观察到的系统中存在事件峰值的风险,当尝试在客户端缓冲可观察性数据时,可能会导致内存峰值和其他相关问题。如果无法插入大批次,用户可以使用异步插入将批处理委托给 ClickHouse。使用异步插入,数据首先插入缓冲区,然后稍后或异步写入数据库存储。


    NEEDS ALT

    在启用异步插入的情况下,当 ClickHouse (1) 接收插入查询时,查询数据将 (2) 立即首先写入内存缓冲区。与 (1) 异步,只有当 (3) 下一次缓冲区刷新发生时,缓冲区的数据才会被排序并作为一部分写入数据库存储。请注意,在刷新到数据库存储之前,查询无法搜索数据;缓冲区刷新是可配置的。

    在缓冲区刷新之前,来自同一客户端或其他客户端的其他异步插入查询的数据可以收集到缓冲区中。从缓冲区刷新创建的部分可能会包含来自多个异步插入查询的数据。通常,这些机制将数据的批处理从客户端转移到服务器端(ClickHouse 实例)。

    有关配置异步插入的完整详细信息,请参见此处,以及深入探讨此处

  • 使用官方客户端 - ClickHouse 在最流行的编程语言中都有客户端。这些客户端针对确保正确执行插入进行了优化,并且可以直接支持异步插入,例如在Go 客户端中,或者在查询、用户或连接级别设置中启用时间接支持。

  • 首选原生格式 - ClickHouse 在插入(和查询)时支持多种输入格式。这与 OLTP 数据库有很大不同,并且使从外部源加载数据变得更容易 - 特别是当与表函数以及从磁盘上的文件加载数据的功能结合使用时。这些格式非常适合临时数据加载和数据工程任务。对于希望获得最佳插入性能的应用程序,用户应使用 Native 格式进行插入。大多数客户端(Go 和 Python)都支持此格式,并确保服务器只需执行最少的工作,因为此格式已经是列式存储的。因此,这将工作强加于为客户端生成列式数据,这应在任何扩展插入的努力中予以考虑。或者,如果首选行格式,用户可以使用RowBinary 格式(如 Java 客户端使用的那样) - 这通常比原生格式更容易编写。就压缩、网络开销和服务器上的处理而言,它比 JSON 等其他行格式更有效。对于希望快速集成的写入吞吐量较低的用户,可以考虑使用 JSONEachRow 格式。用户应该知道,此格式将在 ClickHouse 中产生解析的 CPU 开销。

  • HTTP 或原生协议 - 与许多传统数据库不同,ClickHouse 支持 HTTP 接口。用户可以使用此接口插入和查询数据,使用上述任何格式。这通常优于 ClickHouse 的原生协议,因为它允许使用负载均衡器轻松切换流量。我们预计使用原生协议的插入性能会有细微差异,这会产生稍微少的开销。现有客户端使用其中任何一种协议(在某些情况下两者都使用,例如 Go 客户端)。原生协议确实允许轻松跟踪查询进度。

批量加载数据

对于从 Postgres 批量加载数据,用户可以使用

  • 使用 PeerDB by ClickHouse,这是一种专为将 PostgreSQL 数据库复制到自托管 ClickHouse 和 ClickHouse Cloud 而设计的 ETL 工具。要开始使用,请在PeerDB Cloud上创建一个帐户,并参考文档以获取设置说明。

  • 可以使用 PostgreSQL 表函数直接读取数据,如之前的示例所示。通常适用于基于已知水位线(例如时间戳)进行批量复制的情况,或者是一次性迁移。这种方法可以扩展到数千万行数据。对于需要迁移更大数据集的用户,应考虑使用多个请求,每个请求处理数据的一部分。每个数据块在将其分区移动到最终表之前,都可以使用暂存表。这允许重试失败的请求。有关此批量加载策略的更多详细信息,请参见此处。
  • 数据可以从 PostgreSQL 导出为 CSV 格式。然后,可以使用表函数从本地文件或通过对象存储将其插入到 ClickHouse 中。
需要帮助插入大型数据集吗?

如果您在将大型数据集插入 ClickHouse Cloud 或导入数据时遇到任何错误,请通过 [email protected] 联系我们,我们将提供帮助。