跳转到主要内容
在将数据从 PostgreSQL 复制到 ClickHouse 时,了解 TOAST (超大属性存储技术) 列的局限性及其特殊处理要求非常重要。本指南将帮助您在复制过程中识别并妥善处理 TOAST 列。

PostgreSQL 中的 TOAST 列是什么?

TOAST (The Oversized-Attribute Storage Technique) 是 PostgreSQL 处理大型字段值的机制。当某一行超过最大行大小时 (通常为 2KB,但具体取决于 PostgreSQL 版本和实际配置) ,PostgreSQL 会自动将较大的字段值移到单独的 TOAST 表中,在主表中只保留一个指针。 需要注意的是,在 CDC (变更数据捕获) 过程中,未发生变化的 TOAST 列不会包含在复制流中。如果处理不当,可能会导致复制的数据不完整。 在初始加载 (snapshot) 期间,所有列值 (包括 TOAST 列) 都会被正确复制,不受其大小影响。本指南中提到的限制,主要影响初始加载完成后持续进行的 CDC 过程。 你可以在此处进一步了解 TOAST 及其在 PostgreSQL 中的实现方式:https://www.postgresql.org/docs/current/storage-toast.html

识别表中的 TOAST 列

要判断表中是否存在 TOAST 列,可以使用以下 SQL 查询:
SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod) AS data_type
FROM pg_attribute a
JOIN pg_class c ON a.attrelid = c.oid
WHERE c.relname = 'your_table_name'
  AND a.attlen = -1
  AND a.attstorage != 'p'
  AND a.attnum > 0;
此查询将返回可能会被 TOAST 化的列名及其数据类型。不过,需要注意的是,该查询仅根据数据类型和存储属性识别出具备 TOAST 存储条件的列。要判断这些列是否确实包含 TOAST 化的数据,还需要看这些列中的值是否超过大小限制。数据是否会实际发生 TOAST 化,取决于这些列中存储的具体内容。

确保正确处理 TOAST 列

为确保在复制过程中正确处理 TOAST 列,应将该表的 REPLICA IDENTITY 设置为 FULL。这会告知 PostgreSQL 在执行 UPDATE 和 DELETE 操作时,将完整的旧行写入 WAL,从而确保所有列值 (包括 TOAST 列) 都可用于复制。 你可以使用以下 SQL 命令将 REPLICA IDENTITY 设置为 FULL
ALTER TABLE your_table_name REPLICA IDENTITY FULL;
有关设置 REPLICA IDENTITY FULL 时的性能考量,请参阅这篇博文

未设置 REPLICA IDENTITY FULL 时的复制行为

如果某个包含 TOAST 列的表没有设置 REPLICA IDENTITY FULL,在复制到 ClickHouse 时,可能会出现以下问题:
  1. 在 INSERT 操作中,所有列 (包括 TOAST 列) 都会被正确复制。
  2. 在 UPDATE 操作中:
    • 如果 TOAST 列未被修改,其值在 ClickHouse 中会显示为 NULL 或空值。
    • 如果 TOAST 列被修改,则会被正确复制。
  3. 在 DELETE 操作中,TOAST 列的值在 ClickHouse 中会显示为 NULL 或空值。
这些情况可能会导致 PostgreSQL 源端与 ClickHouse 目标端之间的数据不一致。因此,对于包含 TOAST 列的表,务必设置 REPLICA IDENTITY FULL,以确保数据复制准确完整。

结论

在从 PostgreSQL 复制到 ClickHouse 的过程中,正确处理 TOAST 列对于维护数据完整性至关重要。通过识别 TOAST 列并设置适当的 REPLICA IDENTITY,可以确保数据得到准确、完整的复制。
最后修改于 2026年6月10日