ClickHouse 中存储过程的替代方案
IF/ELSE、循环等) 的传统存储过程。
这是由 ClickHouse 作为分析型数据库的架构特性决定的有意设计选择。
对于分析型数据库,通常不建议使用循环,因为执行 O(n) 个简单查询往往比执行更少但更复杂的查询更慢。
ClickHouse 主要针对以下场景进行了优化:
- 分析型工作负载 - 在大型数据集上执行复杂聚合
- 批处理 - 高效处理海量数据
- 声明式查询 - 只描述要检索哪些数据,而不是描述如何处理这些数据的 SQL 查询
用户自定义函数 (UDFs)
基于 Lambda 的 UDF
示例数据
示例数据
- 不支持循环或复杂控制流
- 不能修改数据 (
INSERT/UPDATE/DELETE) - 不允许使用递归函数
CREATE FUNCTION。
可执行 UDF
参数化视图
示例的样本数据
示例的样本数据
常见用例
Materialized views
可刷新materialized view
外部编排
使用应用代码
- MySQL 存储过程
- ClickHouse 应用代码
关键差异
- 控制流 - MySQL 存储过程使用
IF/ELSE和WHILE循环。在 ClickHouse 中,这类逻辑应在应用代码 (Python、Java 等) 中实现 - 事务 - MySQL 支持用于 ACID 事务的
BEGIN/COMMIT/ROLLBACK。ClickHouse 是面向分析的数据库,针对只追加工作负载进行了优化,而非事务性更新 - 更新 - MySQL 使用
UPDATE语句。对于可变数据,ClickHouse 更适合使用INSERT,并配合 ReplacingMergeTree 或 CollapsingMergeTree - 变量和状态 - MySQL 存储过程可以声明变量 (
DECLARE v_discount) 。在 ClickHouse 中,状态应由应用代码管理 - 错误处理 - MySQL 支持
SIGNAL和异常处理程序。在应用代码中,请使用所选编程语言的原生错误处理机制 (try/catch)
使用工作流编排工具
- Apache Airflow - 调度并监控由 ClickHouse 查询构成的复杂 DAG
- dbt - 使用基于 SQL 的工作流转换数据
- Prefect/Dagster - 基于 Python 的现代编排工具
- Custom schedulers - Cron 作业、Kubernetes CronJob 等
- 完整的编程语言能力
- 更完善的错误处理和重试逻辑
- 与外部系统集成 (API、其他数据库)
- 版本控制和测试
- 监控和告警
- 更灵活的调度
ClickHouse 中预处理语句的替代方案
语法
方法 1:使用 SET
示例表和数据
示例表和数据
方法 2:使用 CLI 参数
参数语法
{parameter_name: DataType}
parameter_name- 参数名称 (不含param_前缀)DataType- 用于将参数转换为该类型的 ClickHouse 数据类型
数据类型示例
- 字符串和数值
- 日期和时间
- 数组
- Map
- 标识符
有关在编程语言客户端中使用查询参数的信息,请参阅相应编程语言客户端的文档。
查询参数的局限性
- 它们主要用于 SELECT 语句 - 对 SELECT 查询的支持最完善
- 它们只能用作标识符或字面量 - 不能替换任意 SQL 片段
- 它们对 DDL 的支持有限 - 在
CREATE TABLE中支持,但在ALTER TABLE中不支持
安全最佳实践
MySQL 协议预处理语句
COM_STMT_PREPARE、COM_STMT_EXECUTE、COM_STMT_CLOSE) 仅提供有限支持,主要是为了让 Tableau Online 这类会将查询封装为预处理语句的工具能够连接。
主要限制:
- 不支持参数绑定 - 不能将
?占位符与绑定参数配合使用 - 查询会被存储,但在
PREPARE阶段不会被解析 - 该实现非常精简,仅用于兼容特定的 BI 工具
摘要
ClickHouse 中存储过程的替代方案
查询参数的用途
- 防止 SQL 注入
- 实现类型安全的参数化查询
- 在应用程序中进行动态过滤
- 复用查询模板
CREATE FUNCTION- 用户自定义函数CREATE VIEW- 视图,包括参数化视图和 materialized view- SQL 语法 - 查询参数 - 完整的参数语法
- 级联 Materialized Views - 高级 materialized view 模式
- 可执行 UDF - 外部函数的执行