ClickHouse SQL防御
更新时间:2026-07-23
本文档介绍ClickHouse引擎支持的SQL防御规则及推荐的SQL写法。SQL防御的功能说明、规则分类、命中动作以及新增规则、查看系统规则等操作方式请参见SQL防御功能。本文仅针对ClickHouse引擎的规则支持情况和使用建议进行说明。
ClickHouse支持的防御规则
ClickHouse除支持通用的静态、动态、运行时规则外,还支持一批针对集群级别(on cluster)操作的独享规则,用于防止在整个集群上执行高风险的DDL和数据变更操作。
静态规则(SQL文本检测)
表一 ClickHouse静态规则
| 规则ID | 规则描述 | 建议阈值 | SQL示例 |
|---|---|---|---|
| static_0001 | SQL中COUNT(DISTINCT)出现次数超限 |
10 | SELECT COUNT(DISTINCT a), COUNT(DISTINCT b) FROM t |
| static_0002 | SQL中使用了NOT IN <subquery> |
— | SELECT * FROM t WHERE id NOT IN (SELECT id FROM t2) |
| static_0003 | SQL中JOIN次数超限 | 20 | 多表JOIN场景 |
| static_0004 | SQL中UNION ALL次数超限 | 20 | 多个SELECT ... UNION ALL SELECT ... |
| static_0005 | 子查询嵌套层数超限 | 20 | SELECT * FROM (SELECT * FROM (SELECT ...)) |
| static_0006 | SQL语句字符串长度超限(单位KB) | 10 | 超长SQL语句 |
| static_0007 | 多表关联时存在笛卡尔积 | — | SELECT * FROM A, B |
ClickHouse独享静态规则(集群级别操作)
表二 ClickHouse集群级别操作规则
| 规则ID | 规则描述 | SQL示例 |
|---|---|---|
| static_0008 | 集群级别(on cluster)执行ALTER TABLE UPDATE操作 |
ALTER TABLE testtb1 ON CLUSTER default_cluster UPDATE price=10.0 WHERE id='100' |
| static_0009 | 集群级别(on cluster)执行ALTER TABLE DELETE操作 |
ALTER TABLE testtb1 ON CLUSTER default_cluster DELETE WHERE id='10' |
| static_0010 | 集群级别(on cluster)执行ALTER TABLE ADD COLUMN操作 |
ALTER TABLE testtb1 ON CLUSTER default_cluster ADD COLUMN testc String |
| static_0011 | 集群级别(on cluster)执行ALTER TABLE DROP COLUMN操作 |
ALTER TABLE testtb1 ON CLUSTER default_cluster DROP COLUMN testc |
| static_0012 | 集群级别(on cluster)执行OPTIMIZE FINAL操作 |
OPTIMIZE TABLE testtb1 ON CLUSTER default_cluster FINAL |
| static_0013 | 集群级别(on cluster)执行DROP TABLE操作 |
DROP TABLE testtb1 ON CLUSTER default_cluster |
| static_0014 | 集群级别(on cluster)执行TRUNCATE TABLE操作 |
TRUNCATE TABLE testtb1 ON CLUSTER default_cluster |
动态规则(执行计划检测)
表三 ClickHouse动态规则
| 规则ID | 规则描述 | 建议阈值 |
|---|---|---|
| dynamic_0001 | 扫描文件数超限 | 100000 |
| dynamic_0002 | 单表操作(SELECT/DELETE/UPDATE/ALTER)涉及分区数超限 | 10000 |
| dynamic_0003 | JOIN右表为分布式表时,右表数据量超限 | 100000000 |
运行时规则(执行中检测)
表四 ClickHouse运行时规则
| 规则ID | 规则描述 | 建议阈值 |
|---|---|---|
| running_0001 | SELECT返回结果行数超限 | 100000 |
| running_0002 | SQL占用内存峰值超限(单位MB) | 按集群配置 |
| running_0003 | SQL已运行时长超限(单位秒) | 按业务需求 |
| running_0004 | SQL已扫描数据量超限(单位GB) | 10240 |
推荐SQL写法
查询明细数据时添加过滤条件和LIMIT,避免触发running_0001返回结果行数超限:
Plain Text
1SELECT *
2FROM user_event_detail
3WHERE event_date = '2026-07-03'
4LIMIT 100;
分区表查询带上分区字段,避免触发dynamic_0002分区数超限:
Plain Text
1SELECT city, count(*) AS cnt
2FROM user_event_detail
3WHERE event_date >= '2026-07-01'
4 AND event_date < '2026-07-04'
5GROUP BY city;
JOIN查询必须包含明确的JOIN条件,避免触发static_0007笛卡尔积拦截:
Plain Text
1SELECT a.user_id, a.event_type, b.name
2FROM user_event_detail a
3JOIN tb_primary_key b
4 ON a.user_id = b.user_id
5WHERE a.event_date = '2026-07-03';
集群级别的DDL和数据变更操作影响范围大,建议在单节点或明确评估影响后执行,避免触发static_0008至static_0014等on cluster规则。
不推荐SQL写法
以下写法可能被防御规则拦截:
Plain Text
1-- 无过滤条件扫描大表(触发 running_0001/running_0004)
2SELECT * FROM user_event_detail;
3
4-- 无JOIN条件笛卡尔积(触发 static_0007)
5SELECT * FROM table_a, table_b;
6
7-- 集群级别删除全表(触发 static_0009/static_0014)
8TRUNCATE TABLE user_event_detail ON CLUSTER default_cluster;
9
10-- NOT IN 子查询(触发 static_0002)
11SELECT * FROM t WHERE id NOT IN (SELECT id FROM t2 WHERE status=0);
12
13-- 过多 COUNT(DISTINCT)(触发 static_0001)
14SELECT COUNT(DISTINCT a), COUNT(DISTINCT b), COUNT(DISTINCT c),
15 COUNT(DISTINCT d), COUNT(DISTINCT e), COUNT(DISTINCT f),
16 COUNT(DISTINCT g), COUNT(DISTINCT h), COUNT(DISTINCT i),
17 COUNT(DISTINCT j), COUNT(DISTINCT k)
18FROM big_table;
说明:以上规则的启用状态、阈值和命中动作均需在防御规则页面配置,配置方式请参见SQL防御功能。
评价此篇文章
