ClickHouse 中的存储过程和查询参数
如果您来自传统的关系数据库,您可能正在寻找 ClickHouse 中的存储过程和预处理语句。本指南解释了 ClickHouse 对这些概念的处理方式,并提供了推荐的替代方案。
ClickHouse 中存储过程的替代方案
ClickHouse 不支持带有控制流逻辑(IF/ELSE、循环等)的传统存储过程。这是基于 ClickHouse 作为分析数据库的架构所做出的有意设计决策。对于分析数据库来说,循环是不鼓励的,因为处理 O(n) 个简单查询通常比处理更少数量的复杂查询要慢。
ClickHouse 针对
- 分析型工作负载 - 对大型数据集进行复杂聚合
- 批量处理 - 高效处理大量数据
- 声明式查询 - SQL 查询,描述要检索的数据,而不是如何处理它
带有过程逻辑的存储过程与这些优化相悖。相反,ClickHouse 提供了与它的优势相符的替代方案。
用户自定义函数 (UDF)
用户自定义函数允许您封装可重用的逻辑,而无需控制流。ClickHouse 支持两种类型
基于 Lambda 的 UDF
使用 SQL 表达式和 lambda 语法创建函数
示例数据的示例
限制
- 没有循环或复杂的控制流
- 无法修改数据 (
INSERT/UPDATE/DELETE) - 不允许递归函数
请参阅 CREATE FUNCTION 以获取完整的语法。
可执行 UDF
对于更复杂的逻辑,请使用调用外部程序的的可执行 UDF
可执行 UDF 可以在任何语言(Python、Node.js、Go 等)中实现任意逻辑。
请参阅 可执行 UDF 以获取详细信息。
参数化视图
参数化视图充当返回数据集的函数。它们非常适合具有动态筛选的重用查询
示例数据示例
常见用例
请参阅 参数化视图 部分以获取更多信息。
物化视图
物化视图非常适合预先计算传统上在存储过程中完成的昂贵聚合。如果您来自传统数据库,可以将物化视图视为一个 INSERT 触发器,它会在数据插入到源表时自动转换和聚合数据
可刷新物化视图
用于计划的批量处理(例如夜间存储过程)
请参阅 级联物化视图 以获取高级模式。
外部编排
对于复杂的业务逻辑、ETL 工作流或多步骤流程,始终可以在 ClickHouse 外部使用语言客户端来实现逻辑。
使用应用程序代码
这是一个并排比较,显示了 MySQL 存储过程如何转换为带有 ClickHouse 的应用程序代码
- MySQL 存储过程
- ClickHouse 应用程序代码
下面的示例在 ClickHouse 中使用查询参数。如果您不熟悉 ClickHouse 中的查询参数,请跳至 “ClickHouse 中预处理语句的替代方案”。
主要区别
- 控制流 - MySQL 存储过程使用
IF/ELSE、WHILE循环。在 ClickHouse 中,在您的应用程序代码(Python、Java 等)中实现此逻辑 - 事务 - MySQL 支持
BEGIN/COMMIT/ROLLBACK以进行 ACID 事务。ClickHouse 是一种针对追加型工作负载优化的分析数据库,而不是事务更新 - 更新 - MySQL 使用
UPDATE语句。ClickHouse 倾向于使用 ReplacingMergeTree 或 CollapsingMergeTree 进行可变数据 - 变量和状态 - MySQL 存储过程可以声明变量 (
DECLARE v_discount)。使用 ClickHouse,在您的应用程序代码中管理状态 - 错误处理 - MySQL 支持
SIGNAL和异常处理程序。在应用程序代码中,使用您语言的本机错误处理 (try/catch)
何时使用哪种方法
- OLTP 工作负载(订单、付款、用户帐户)→ 使用带有存储过程的 MySQL/PostgreSQL
- 分析型工作负载(报告、聚合、时间序列)→ 使用带有应用程序编排的 ClickHouse
- 混合架构 → 同时使用两者!将 OLTP 中的事务数据流式传输到 ClickHouse 进行分析
使用工作流编排工具
- Apache Airflow - 计划和监控 ClickHouse 查询的复杂 DAG
- dbt - 使用基于 SQL 的工作流转换数据
- Prefect/Dagster - 现代 Python 基于的编排
- 自定义调度程序 - Cron 作业、Kubernetes CronJobs 等。
外部编排的好处
- 完整的编程语言功能
- 更好的错误处理和重试逻辑
- 与外部系统的集成(API、其他数据库)
- 版本控制和测试
- 监控和警报
- 更灵活的调度
ClickHouse 中预处理语句的替代方案
虽然 ClickHouse 没有 RDBMS 意义上的传统“预处理语句”,但它提供了 查询参数,它们具有相同的目的:安全的参数化查询,可防止 SQL 注入。
语法
有两种定义查询参数的方法
方法 1:使用 SET
示例表和数据
方法 2:使用 CLI 参数
参数语法
参数使用以下方式引用:{parameter_name: DataType}
parameter_name- 参数的名称(没有param_前缀)DataType- 要将参数转换为的 ClickHouse 数据类型
数据类型示例
示例表和数据
- 字符串和数字
- 日期和时间
- 数组
- 映射
- 标识符
有关在 语言客户端 中使用查询参数的信息,请参阅您感兴趣的特定语言客户端的文档。
查询参数的限制
查询参数不是通用的文本替换。它们具有特定的限制
- 它们主要用于 SELECT 语句 - 在 SELECT 查询中的支持最好
- 它们作为标识符或字面量起作用 - 它们不能替代任意 SQL 片段
- 它们具有有限的 DDL 支持 - 它们受支持在
CREATE TABLE中,但不受支持在ALTER TABLE中
有效示例
无效示例
安全最佳实践
始终对用户输入使用查询参数
验证输入类型
MySQL 协议预处理语句
ClickHouse 的 MySQL 接口 包含对预处理语句(COM_STMT_PREPARE、COM_STMT_EXECUTE、COM_STMT_CLOSE)的最小支持,主要目的是为了与 Tableau Online 等包装查询在预处理语句中的工具兼容。
主要限制
- 不支持参数绑定 - 您无法使用
?占位符和绑定参数 - 查询在
PREPARE期间存储但未解析 - 实现最少,专为特定的 BI 工具兼容性而设计
无效示例
改用 ClickHouse 的本机查询参数。 它们提供完整的参数绑定支持、类型安全性和 SQL 注入预防,适用于所有 ClickHouse 接口
有关更多详细信息,请参阅 MySQL 接口文档 和 关于 MySQL 支持的博客文章。
摘要
ClickHouse 存储过程的替代方案
| 传统存储过程模式 | ClickHouse 替代方案 |
|---|---|
| 简单的计算和转换 | 用户自定义函数 (UDF) |
| 可重用的参数化查询 | 参数化视图 |
| 预先计算的聚合 | 物化视图 |
| 计划的批量处理 | 可刷新物化视图 |
| 复杂的多步骤 ETL | 链式物化视图或外部编排(Python、Airflow、dbt) |
| 具有控制流的业务逻辑 | 应用程序代码 |
查询参数的使用
查询参数可用于
- 防止 SQL 注入
- 具有类型安全的参数化查询
- 应用程序中的动态筛选
- 可重用的查询模板
相关文档
CREATE FUNCTION- 用户自定义函数CREATE VIEW- 包括参数化和物化视图- SQL 语法 - 查询参数 - 完整的参数语法
- 级联物化视图 - 高级物化视图模式
- 可执行 UDF - 外部函数执行