ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

DeepSeek总结的pg_clickhouse 与 chdb 更新:编码、嵌套与类型

DeepSeek总结的pg_clickhouse 与 chdb 更新:编码、嵌套与类型 pg_clickhouse 与 chdb 更新编码、嵌套与类型发布日期2026-09-30T16:29:40.227Z作者David Wheeler分类产品摘要最新的 pg_clickhouse 和 chdb 扩展版本改进了 ClickHouse 与 Postgres 之间的字符编码、间隔处理、嵌套数据、JSON 和类型映射。pg_clickhouse 与 chdb 更新编码、嵌套与类型现已在 GitHub 和 PGXN 上发布pg_clickhouse v0.11.0 和 chdb 扩展 v0.1.2 继续我们坚定不移地专注于跨数据库兼容性。其中大量增强源自我们的仅头文件 C 库 clickhouse-c 和 pg-clickhouse-c。让我们看看这些版本中仅有的三项更改。好一个字符 {#what_a_character}首先是字符编码。在开发 chdb 扩展文章的基准测试过程中我发现 pg-clickhouse-c 没有验证文本列的字符编码。我的同事 Philip 迅速修补了该库使其在任何基于文本或 JSON 的类型1包含违反数据库编码的字节时抛出异常。此修复随 chdb v0.1.1 发布但我们推迟了 pg_clickhouse 的发布以避免对任何拥有读取无效编码数据的现有外部表的用户造成错误。pg_clickhouse v0.11.0 添加了一个新的外部服务器选项check_encoding它提供编码错误处理器。选项包括fail默认抛出错误remove移除无效字节replace在 UTF-8 编码下将无效字节替换为 Unicode 替换字符对于其他编码等同于removetruncate在第一个无效字节处截断文本chdb_hook v0.1.2 为其 COPY 和 CREATE TABLE 命令提供了相同的选项。两者都允许你解决类似以下的错误ERROR: invalid byte sequenceforencodingUTF8:0x81更改 pg_clickhouse 服务器配置check_encoding以消除错误。最易读的将是replaceALTER SERVER ch_server_name OPTIONS (ADD check_encoding replace);对于 chdb_hook将其作为 COPY 或 CREATE TABLE 选项传入CREATE TABLE logs () WITH ( copy_from s3://chdb-lakedata-public/logs/logs-2026-08-26.csv, format CSVWithNames, check_encoding replace );对于 UTF-8 编码的数据库无效字节将被替换为try# SELECT * FROM ch_table ORDER BY id;id|name -------------1|Barrack2|Aley3|Leopold4|Anne对于其他数据库编码有问题的字符将被直接移除try# SELECT * FROM ch_table ORDER BY id;id|name -------------1|Barrack2|Aley3|Leopold4|Ann另一方面如果你需要保留字节兼容性则需要将有问题的列映射为byteaALTER FOREIGN TABLE ch_table ALTER name TYPE bytea;这将保留逐字节的二进制数据try# SELECT * FROM ch_table ORDER BY id;id|name ----------------------1|\x4261727261636b2|\x416c6500793|\x4c656f706f6c644|\x416e006e8165(4rows)但请注意转换为文本将会失败。间隔有效 {#intervalid}ClickHouse 支持众多间隔类型IntervalNanosecond、IntervalHour、IntervalDay、IntervalYear以及介于两者之间的所有类型。在以前的版本中pg_clickhouse 不支持这些类型尝试导入使用其中一种类型的 ClickHouse 表会返回错误。不再如此。pg_clickhouse v0.11.0 和 chdb_hook 0.1.2 将这些类型导入为 Postgresinterval列。因此给定一个使用例如IntervalMillisecond的 ClickHouse 表如下面duration列所示CREATE TABLE logs ( req_id Int64 NOT NULL, start_at DateTime64(6, UTC) NOT NULL, duration IntervalMillisecond NOT NULL, resource Text NOT NULL, method Enum8(GET 1, HEAD, POST, PUT, DELETE, PATCH) NOT NULL, node_id Int64 NOT NULL, response Int32 NOT NULL ) ENGINE MergeTree ORDER BY start_at;导入时pg_clickhouse 会创建一个带有duration interval列的表列类型可空req_idbigintnot nullstart_attimestamp(6) with time zonenot nulldurationintervalnot nullresourcetextnot nullmethodtextnot nullnode_idbigintnot nullresponseintegernot null当然下推也有效。假设你想统计昨天一天结束前完成的所有事务。只需将持续时间加到开始时间try# EXPLAIN (VERBOSE, COSTS OFF)SELECT COUNT(*)FROM logs WHERE start_at durationdate_trunc(day, now());QUERY PLAN ----------------------------------------------------------------------------------------------------------- Foreign Scan Output:(count(*))Relations: Aggregate on(logs)Remote SQL: SELECT count(*)FROMdefault.logs WHERE(((start_atduration)toStartOfDay(now64())))(4rows)EXPLAIN (VERBOSE)输出显示了在 ClickHouse 上执行的远程查询它显然将start_at duration下推到 ClickHouse 中执行当然还有COUNT()聚合2。同样的模式适用于 chdb_hook v0.1.2它将 chDB 间隔类型导入为 Postgresinterval值。两个扩展也都允许将间隔类型改为导入为bigint。只需创建带有duration bigint的外部表或复制目标表扩展会完成其余工作。嵌套本能 {#nesting_instinct}pg_clickhouse 的 http 驱动自 v0.1 起就支持 JSON 类型二进制驱动自 v0.3 起也支持。然而尽管它会下推 JSON 属性访问器例如SELECT * FROM things ORDER BY data - name;ClickHouse 会返回错误DB::Exception: Data types Variant/Dynamic are not allowedinORDER BY keys, because it can lead to unexpected results. Consider using a subcolumn with a specific datatypeinstead此错误源于 ClickHouse JSON 对象的实现ClickHouse 想要知道 JSON 属性存在才能排序。ClickHouse 25.3 参数化子列保证了属性存在。一个示例CREATE TABLE things ( id Int32 NOT NULL, data JSON( id UInt32, name String, size Enum(small, medium, large), stocked Bool ) NOT NULL ) ENGINE MergeTree PARTITION BY id ORDER BY (id);以前pg_clickhouse 无法导入参数化 JSON 列但 v0.11.0以及 chdb_hook v0.1.2简单地将其映射为 jsonb或 json现在对属性的ORDER BY可以正确下推try# SELECT * FROM things ORDER BY data - name;id|data ---------------------------------------------------------------------4|{id:4,name:doodad,size:large,stocked:false}3|{id:3,name:gizmo,size:medium,stocked:true}2|{id:2,name:sprocket,size:small,stocked:true}1|{id:1,name:widget,size:large,stocked:true}(4rows)类似地pg_clickhouse v0.11.0 和 chdb_hook v0.1.2 改进了对未展平 Nested 类型的支持如下例所示CREATE TABLE visits( visit_id UInt64, user_id UInt64, goals Nested( serial UInt32, order_id String ) ) ENGINE MergeTree ORDER BY visit_id SETTINGS flatten_nested 0;flatten_nested0指示 ClickHouse 创建一个单一的goals列格式为Tuple(serial UInt32, order_id String)的数组而不是为每个字段单独的数组列。以前两个扩展都不支持这种结构。现在它们提供两种映射。默认情况下IMPORT FOREIGN SCHEMA 和 chdb_hook 的 COPY 与 CREATE TABLE 命令将未展平的 Nested 列映射为二维文本数组列类型visit_idnumeric(20,0)user_idnumeric(20,0)goalstext[][]这会将 Nested 值中的每一项映射为每种类型文本表示的数组try# SELECT * FROM nest_bin.visits WHERE visit_id 3 ORDER BY visit_id;visit_id|user_id|goals ------------------------------------1|1|{{1,xx},{2,yy}}(1row)goals数组包含两个数组每个数组有两个文本值第一个用于serial第二个用于order_id。这种结构以牺牲数据类型为代价保留了数据不过在 pg_clickhouse 表上执行 INSERT 会在插入 ClickHouse 之前正确转换类型INSERT INTO visits VALUES (2, 2, ARRAY[ [3, aa], [4, bb] ]);但我们可以做得更好。pg_clickhouse v0.11.0 还允许将 Nested 值映射到自定义复合类型只要顺序、类型和命名完全一致。给定为goals定义的 Nested 类型Tuple(serial UInt32, order_id String)我们可以创建一个具有对应名称和类型的类型并将其放入外部表CREATE TYPE goal_type AS (serial bigint, order_id text); ALTER FOREIGN TABLE visits ALTER goals TYPE goal_type[];现在 Nested 元组转换为复合类型try# SELECT * FROM nest_bin.visits WHERE visit_id 3 ORDER BY visit_id;visit_id|user_id|goals ----------------------------------------1|1|{(1,xx),(2,yy)}2|2|{(3,aa),(4,bb)}当然我们也可以按此格式 INSERT 数据INSERT INTO visits VALUES (3, 3, ARRAY[row(5, jj), row(6, zz)]::goal_type[]);同样的模式适用于 chdb_hook v0.1.2在处理从 ClickHouse 或 chDB 导出的嵌套数据时Postgres 目标表可以使用多维值数组或适当结构的复合类型数组CREATE TYPE event_status AS ENUM (new, done); CREATE TYPE event_point AS (x integer, y integer); CREATE TYPE event_label AS (key text, value bigint); CREATE TYPE event_item AS (id integer, name text); CREATE TABLE events ( status event_status, point event_point, labels event_label[], items event_item[] );然后在COPY查询中使用相应的数据类型定义或依赖某个*WithNamesAndTypes格式来导入数据。COPY events FROM s3://chdb-lakedata-public/examples/events.parquet ( structure $$ status Enum8(new 1, done 2), point Tuple(Int32, Int32), labels Map(String, Int64), items Array(Tuple(id Int32, name String)) $$ );这里我们为嵌套类型使用了Array()如果数据是从 ClickHouse 以未展平flatten_nested0结构导出的你可以改用NestedCOPY events FROM s3://chdb-lakedata-public/examples/events.parquet ( structure $$ status Enum8(new 1, done 2), point Tuple(Int32, Int32), labels Map(String, Int64), items Nested(id Int32, name String) $$ );零碎事项 {#odds_and_ends}pg_clickhouse v0.11.0 还附带了许多其他值得一提的改进眼尖的读者无疑已经注意到除了间隔映射之外大整数类型现在映射到适当的 Postgres numeric许多其他 ClickHouse 数据类型现在也映射到适当的 Postgres 对应类型ClickHousePostgreSQLInt128numeric(39,0)Int256numeric(77,0)UInt64numeric(20,0)UInt128numeric(39,0)UInt256numeric(78,0)BFloat16float4TimetimeTime64§timeTuple(…)text[]Map(K,V)text[][]LineStringpathMultiLineStringpath[]MultiPolygonpolygon[][]PointpointRingpolygonPolygonpolygon[]相同的映射适用于 chdb 扩展 v0.1.2。最初的clickhouse_raw_query()函数已在 v0.10.0 中弃用现已被移除。请更新你的代码使用clickhouse_query(server, sql)读取行使用CALL clickhouse_perform(server, sql)运行不返回结果的语句。此版本放弃了对 PostgreSQL 13 的支持该版本自 2025 年 9 月起已不再受 Postgres 社区支持。一项社区贡献添加了对 PostgreSQLsha224()、sha256()、sha384()和sha512()函数的下推支持以及对 pgcrypto 扩展digest()函数支持的常量算法调用。查看完整的 pg_clickhouse 更改和 chdb 更改以了解更多细节包括错误修复。然后从通常的地方获取它们。对于 pg_clickhousePGXNGitHubDocker对于 chdb 扩展PGXNGitHub立即开始使用 ClickHouse Managed Postgres有兴趣了解 ClickHouse Managed Postgres 如何在你的数据上运作吗几分钟内开始使用 ClickHouse Cloud并获得 300 美元免费额度。注册是的JSON 按定义偏好 UTF-8除非它并非如此。Postgres 中的 JSON 数据必须始终使用数据库编码。 ↩︎不幸的是ClickHouse 间隔类型本身尚不支持聚合因此例如avg(duration)会失败。但请关注 26.10 中的avg和sum支持。 ↩︎
返回列表