Skip to main content
ClickHouse 支持多种类型的用户自定义函数 (UDFs) :
  • 可执行 UDFs 会启动外部程序或脚本 (Python、Bash 等) ,并通过 STDIN / STDOUT 以流式方式向其传输数据块。可用于在无需重新编译 ClickHouse 的情况下集成现有代码或工具。与进程内方案相比,它们的单次调用开销更高,因此更适合较重的逻辑,或需要不同运行时的场景。
  • SQL UDFs 使用 CREATE FUNCTION 通过纯 SQL 定义。它们会被内联/展开到查询计划中 (不存在进程边界) ,因此开销较低,非常适合复用表达式逻辑或简化复杂的计算列。
  • Experimental WebAssembly UDFs 会在服务器进程内的沙箱中运行编译为 WebAssembly 的代码。与外部可执行程序相比,它们的单次调用开销更低;与原生扩展相比,又具备更好的隔离性,因此适合用可编译为 WASM 的语言 (如 C/C++/Rust) 编写自定义算法。
  • Experimental 基于 driver 的可执行 UDFs 允许由运维人员提供的 “driver” 在函数创建时,将 CREATE FUNCTION ... ENGINE = DriverName(...) AS '...' 中提供的代码片段转换为可执行 UDF (例如通过编译) 。它们构建在可执行 UDFs 之上,并且需要服务器端 driver 配置。

可执行用户自定义函数

在 ClickHouse Cloud 中,可执行 UDF 目前处于 Public Beta 阶段,并通过 Cloud 控制台 UI 创建。有关 Cloud 特定工作流,请参见 Cloud 中的用户自定义函数
ClickHouse 可以调用任意外部可执行程序或脚本来处理数据。 可执行用户自定义函数的配置可位于一个或多个 XML 文件中。 配置路径由 user_defined_executable_functions_config 参数指定。 函数配置包含以下设置: 命令必须从 STDIN 读取参数,并将结果输出到 STDOUT。命令必须以迭代方式处理参数。也就是说,处理完一批参数后,它必须等待下一批参数。

可执行用户自定义函数

示例

来自内联脚本的 UDF

通过 XML 或 YAML 配置手动创建 test_function_sum,并将 execute_direct 指定为 0
文件 test_function.xml (默认路径设置下为 /etc/clickhouse-server/test_function.xml) 。
/etc/clickhouse-server/test_function.xml

Query
Result

基于 Python 脚本的 UDF

在此示例中,我们将创建一个 UDF,它从 STDIN 读取一个值,并将其作为字符串返回。 使用 XML 或 YAML 配置创建 test_function
文件 test_function.xml (默认路径设置下为 /etc/clickhouse-server/test_function.xml) 。
/etc/clickhouse-server/test_function.xml

user_scripts 文件夹中创建脚本文件 test_function.py (默认路径设置下为 /var/lib/clickhouse/user_scripts/test_function.py) 。
Query
Result

STDIN 读取两个值,并将它们的和作为 JSON 对象返回

使用 XML 或 YAML 配置,以命名参数和 JSONEachRow 格式创建 test_function_sum_json
文件 test_function.xml (默认路径设置下为 /etc/clickhouse-server/test_function.xml) 。
/etc/clickhouse-server/test_function.xml

user_scripts 文件夹中创建脚本文件 test_function_sum_json.py (默认路径设置下为 /var/lib/clickhouse/user_scripts/test_function_sum_json.py) 。
Query
Result

command 设置中使用参数

可执行用户自定义函数可以接收在 command 设置中配置的常量参数 (仅适用于 executable 类型的用户自定义函数) 。 此外,还需要启用 execute_direct 选项,以避免 shell 参数展开漏洞。
文件 test_function_parameter_python.xml (默认路径设置下为 /etc/clickhouse-server/test_function_parameter_python.xml) 。
/etc/clickhouse-server/test_function_parameter_python.xml

user_scripts 文件夹中创建脚本文件 test_function_parameter_python.py (默认路径设置下为 /var/lib/clickhouse/user_scripts/test_function_parameter_python.py) 。
Query
Result

通过 shell 脚本创建 UDF

在本示例中,我们将创建一个 shell 脚本,把每个值乘以 2。
文件 test_function_shell.xml (默认路径配置下为 /etc/clickhouse-server/test_function_shell.xml) 。
/etc/clickhouse-server/test_function_shell.xml

user_scripts 文件夹中创建脚本文件 test_shell.sh (默认路径配置下为 /var/lib/clickhouse/user_scripts/test_shell.sh) 。
/var/lib/clickhouse/user_scripts/test_shell.sh
Query
Result

错误处理

如果数据无效,某些函数可能会抛出异常。 此时,查询会被取消,并向客户端返回错误信息。 对于分布式处理,当其中一台服务器上发生异常时,其他服务器也会尝试中止该查询。

参数表达式的求值

在几乎所有编程语言中,对于某些运算符,某个参数可能不会被求值。 通常是运算符 &&||?:。 在 ClickHouse 中,函数 (运算符) 的参数始终都会被求值。 这是因为系统会一次性对整块列数据进行求值,而不是逐行分别计算。

分布式查询处理中函数的执行

在分布式查询处理中,会尽可能多地在远程服务器上完成查询处理的各个阶段,其余阶段 (合并中间结果及之后的所有操作) 则在请求方服务器上完成。 这意味着,函数可能会在不同的服务器上执行。 例如,在查询 SELECT f(sum(g(x))) FROM distributed_table GROUP BY h(y), 中:
  • 如果 distributed_table 至少有两个分片,则函数 ‘g’ 和 ‘h’ 在远程服务器上执行,而函数 ‘f’ 在请求方服务器上执行。
  • 如果 distributed_table 只有一个分片,则 ‘f’、‘g’ 和 ‘h’ 这几个函数都会在该分片所在的服务器上执行。
函数的结果通常与它在哪台服务器上执行无关。但有时这一点很重要。 例如,使用字典的函数会使用其运行所在服务器上的字典。 另一个例子是 hostName 函数,它返回其运行所在服务器的名称,以便在 SELECT 查询中按服务器进行 GROUP BY 如果查询中的某个函数是在请求方服务器上执行的,但你需要它在远程服务器上执行,可以将其包裹在 ‘any’ 聚合函数中,或者将其添加到 GROUP BY 键中。

SQL 用户自定义函数

可使用 CREATE FUNCTION 语句基于 Lambda 表达式创建自定义函数。要删除这些函数,请使用 DROP FUNCTION 语句。

WebAssembly 用户自定义函数

WebAssembly 用户自定义函数 (WASM UDF) 允许你在 ClickHouse 服务器进程中运行编译为 WebAssembly 的自定义代码。

快速入门

在 ClickHouse 配置中启用 Experimental WebAssembly 支持:
将编译好的 WASM 模块插入系统表:
使用你的 WASM 模块创建函数:
在查询中使用此函数:

更多信息

更多详情请参阅WebAssembly 用户自定义函数文档。

基于驱动的可执行用户自定义函数

这是一项 Experimental 功能,未来的发行版中可能会引入不向后兼容的变更。请通过 allow_experimental_executable_udf_drivers 服务器设置启用它。
驱动 是由运维方提供的一种适配器,用于将用户编写的代码片段转换为可运行的可执行 UDF。当使用 ENGINE = DriverName(...) 创建函数时,ClickHouse 会运行该驱动的 create_command,并向其传递函数签名和代码主体;驱动会对代码主体进行编译或其他处理,然后输出一份可执行 UDF 配置,供 ClickHouse 存储和加载。 这样,管理员就能为用户提供一种安全且受限的方式,用任意语言定义函数 (例如,在沙箱容器中编译的 C) ,而无需授予他们访问服务器配置文件或文件系统的权限。可用驱动的范围完全由运维方控制。

启用驱动

Driver-based executable UDFs 默认处于禁用状态。要启用它们,请按以下步骤操作:
  1. 在服务器配置中启用 Experimental 功能开关:
  2. user_defined_executable_function_drivers_config 配置为指向一个或多个驱动配置文件 (支持 glob) ,并可选择设置 dynamic_user_defined_executable_functions_path,即用于存储生成的可执行 UDF 配置的目录:
驱动 registry 会在服务器启动时加载,并在执行 SYSTEM RELOAD CONFIG 时刷新,因此无需重启服务器即可添加、更改或移除驱动。

驱动程序配置

驱动程序由一个以 <driver> 为顶层元素的 XML (或 YAML) 文件定义。支持以下字段: 驱动程序配置示例:

驱动调用约定

运行 CREATE FUNCTION 时,会在设置好已配置的 env 变量后调用 create_command,并传入以下参数:
  • --name <function_name>
  • --return <return_type> (如果存在 RETURNS 子句)
  • --args <signature> (如果存在 ARGUMENTS 子句) ,其中 signature 是声明的参数列表,例如 x UInt8, y DateTime
  • 对于在 ENGINE = DriverName(key = value) 中提供的每个已声明 engine 参数,都会传入 --<key> <value>
用户代码主体 (即 AS 后面的文本) 会被发送到该命令的标准输入。该命令必须将可执行 UDF 的配置输出到标准输出。格式会自动检测:以 < 开头的输出会被视为 XML,否则视为 YAML。生成配置中定义的函数名必须与正在创建的函数名一致。如果 create_command 以非零状态退出,该 statement 会失败,并抛出包含退出码和驱动标准错误输出的异常。 如果存在 drop_command,则在删除函数时也会以相同方式调用它 (但不会通过 stdin 传入代码主体) 。

创建函数

ClickHouse 运行 driver 的 create_command,将生成的配置写入 dynamic_user_defined_executable_functions_path,随后现有的可执行 UDF 加载器会检测并加载该配置。之后,这个函数就可以像其他函数一样调用。

删除函数

DROP FUNCTION 会调用驱动程序的 drop_command (如果存在) ,删除生成的动态配置以及每个函数的工作目录,重新加载可执行 UDF 加载器,并删除已持久化的查询。

持久化与重启

原始查询会以 ATTACH FUNCTION ... 语句的形式保存在用户定义 SQL 对象目录中,因此服务器重启后该函数仍会保留。启动时,会直接加载 dynamic_user_defined_executable_functions_path 中生成的配置,而无需重新运行驱动程序。如果已持久化的 ATTACH FUNCTION 没有对应的已生成配置 (例如动态目录丢失了) ,则会重新运行驱动程序来重新创建它。

限制

  • 该功能为 Experimental,受 allow_experimental_executable_udf_drivers 控制。
  • 基于 driver 的函数不支持复制型用户自定义函数存储 (ON CLUSTER<user_defined_zookeeper_path>) ,因为被复制的只有发起查询,不包括生成的制品。
  • 对已备份的基于 driver 的函数执行 RESTORE 时,会保留查询,但不会重新运行 driver;生成的 configuration 会在重启恢复期间稍后物化。

C 驱动程序示例

源码树在 programs/server/user_defined_executable_function_drivers_config.d/ 下提供了一些概念验证驱动,用于编译并运行 C 函数体。它们仅作为示例,不会随软件包一起安装
  • DockerC - 在经过沙箱隔离的 Docker 容器内编译并运行代码 (--network=none --read-only --cap-drop=ALL --security-opt=no-new-privileges,以及内存/CPU/PID 限制) ,并输出一个 executable_pool UDF。
  • GVisorC - 一种变体,在 gVisor runsc 运行时下运行已编译的可执行文件。
  • UnsafeC - 直接在主机上编译并运行代码,不使用沙箱。顾名思义,它不提供任何隔离,仅适用于受信任环境和测试。
这些示例驱动程序可作为起点;在将它们暴露给不受信任的用户之前,请先根据您的环境审查并加固其沙箱隔离机制。
最后修改于 2026年7月24日