Clickhouse 中的replace语法

 1. 结果

1.1 版本23.6.1.1524

SQL Dynamic Column Selection with ClickHouse

REPLACE子句在SELECT语句中位于COLUMNS选择之后,但在WHERE子句之前。这意味着REPLACE操作会先于WHERE过滤执行。

此外,文档还指出:

"We can see that those two columns have both been replaced and the other columns are as they were in the previous query."

这进一步说明REPLACE操作是在整个结果集上执行的,而不是在WHERE过滤之后。

因此,我们可以得出结论,在ClickHouse中,查询结果集字段的动态替换(REPLACE)的优先级高于WHERE子句的过滤操作。REPLACE会先执行,然后才是WHERE过滤。

1.2 版本24.3

24.3版本:将where和replace的执行逻辑合并到投影表达式中,所以不会出现这种冲突现象

2. 不同版本测试过程

2.1 23.6版本

ck-test :) 
 CREATE TABLE default.students
(
    `id` UInt32,
    `name` String,
    `age` UInt8
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/default/students', '{replica}')
ORDER BY id
SETTINGS index_granularity = 8192
;

CREATE TABLE default.students
(
    `id` UInt32,
    `name` String,
    `age` UInt8
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/default/students', '{replica}')
ORDER BY id
SETTINGS index_granularity = 8192

Query id: 70fece67-c230-47c0-b638-0a1d878d328d

Ok.

0 rows in set. Elapsed: 0.104 sec. 

ck-test :) 

insert into students values(1,'Loe',18);

INSERT INTO students FORMAT Values

Query id: f534c2a2-c919-4ed0-854b-3f1351127589

Ok.

1 row in set. Elapsed: 0.021 sec. 

ck-test :) select * from students;

SELECT *
FROM students

Query id: d45396c8-d2d5-4cc8-bbeb-da3be6b64849

┌─id─┬─name─┬─age─┐
│  1 │ Loe  │  18 │
└────┴──────┴─────┘

1 row in set. Elapsed: 0.003 sec. 

ck-test :) 
SELECT * REPLACE ('LoL' AS name) FROM students where name = 'Leo';


SELECT * REPLACE 'LoL' AS name
FROM students
WHERE name = 'Leo'

Query id: 22ab5c71-8725-4a7c-b99f-85ef070fe723

Ok.

0 rows in set. Elapsed: 0.002 sec. 
ck-test :) explain plan SELECT * REPLACE ('LoL' AS name) FROM students where name = 'Leo';

EXPLAIN
SELECT * REPLACE 'LoL' AS name
FROM students
WHERE name = 'Leo'

Query id: 36fd8fd7-8a15-44bc-998b-8f531d176a4b

┌─explain─────────────────────────────────────┐
│ Expression ((Projection + Before ORDER BY)) │
│   Filter (WHERE)                            │
│     ReadFromMergeTree (default.students)    │
└─────────────────────────────────────────────┘

3 rows in set. Elapsed: 0.002 sec. 

ck-test :) explain syntax SELECT * REPLACE ('LoL' AS name) FROM students where name = 'Leo';

EXPLAIN SYNTAX
SELECT * REPLACE 'LoL' AS name
FROM students
WHERE name = 'Leo'

Query id: 1e76e5f8-6053-4100-a423-4366a486bac7

┌─explain────────────┐
│ SELECT             │
│     id,            │
│     'LoL' AS name, │
│     age            │
│ FROM students      │
│ WHERE 0            │
└────────────────────┘

6 rows in set. Elapsed: 0.002 sec.

2.2 24.3版本

localhost :) SELECT * REPLACE ('LoL' AS name) FROM students where name = 'Leo';

SELECT * REPLACE 'LoL' AS name
FROM students
WHERE name = 'Leo'

Query id: 900bebff-2c32-4186-80cd-00828a74089f

   ┌─id─┬─name─┬─age─┐
1. │ 12 │ LoL  │  31 │
   └────┴──────┴─────┘

1 row in set. Elapsed: 0.004 sec. 
localhost :) explain plan SELECT * REPLACE ('LoL' AS name) FROM students where name = 'Leo';

EXPLAIN
SELECT * REPLACE 'LoL' AS name
FROM students
WHERE name = 'Leo'

Query id: c184e4e2-92a6-46a7-ad46-332b5df62bef

   ┌─explain───────────────────────────────────┐
1. │ Expression ((Project names + Projection)) │
2. │   Expression                              │
3. │     ReadFromMergeTree (default.students)  │
   └───────────────────────────────────────────┘

3 rows in set. Elapsed: 0.002 sec. 

localhost :) explain syntax SELECT * REPLACE ('LoL' AS name) FROM students where name = 'Leo';

EXPLAIN SYNTAX
SELECT * REPLACE 'LoL' AS name
FROM students
WHERE name = 'Leo'

Query id: 1908bf5f-1c50-4f67-a39b-07360de52e87

   ┌─explain────────────┐
1. │ SELECT             │
2. │     id,            │
3. │     'LoL' AS name, │
4. │     age            │
5. │ FROM students      │
6. │ WHERE 0            │
   └────────────────────┘

6 rows in set. Elapsed: 0.003 sec. 

2.3 核心不同

23.6
┌─explain─────────────────────────────────────┐
│ Expression ((Projection + Before ORDER BY)) │
│   Filter (WHERE)                            │
│     ReadFromMergeTree (default.students)    │
└─────────────────────────────────────────────┘

24.3
   ┌─explain───────────────────────────────────┐
1. │ Expression ((Project names + Projection)) │
2. │   Expression                              │
3. │     ReadFromMergeTree (default.students)  │
   └───────────────────────────────────────────┘

上面测试过程使用到了一些clickhouse的基础指令,下面给出相关使用介绍。

Prewhere

PREWHERE 只能在 *MergeTree 家族树里使用;

1. WHERE子句:

  • WHERE子句在查询中是最后执行的,它作用于从表中读取的所有数据。
  • WHERE子句可以包含任意条件,并且可以使用各种函数和操作符进行数据筛选。
  • WHERE子句可以使用索引来加速查询,优化性能。

2. PREWHERE子句:

  • PREWHERE子句在WHERE子句之前执行,它作用于从数据源读取的数据。
  • PREWHERE子句通常用于过滤数据源中不必要的行,以减少读取和处理的数据量,提升性能。
  • PREWHERE子句只能包含简单的条件,不能使用聚合函数、多个列的条件判断等复杂操作。
  • PREWHERE子句不能使用索引来加速查询。

EXPLAIN Types

  • AST — Abstract syntax tree.
  • SYNTAX — Query text after AST-level optimizations.
  • QUERY TREE — Query tree after Query Tree level optimizations.
  • PLAN — Query execution plan.
  • PIPELINE — Query execution pipeline.

可添加参数:

PLAN: 用于查看执行计划,可以指定五个参数;

header:打印计划中各个步骤的 header 说明,默认 0(关闭);

description:打印计划中各个步骤的描述,默认 1(开启);

indexes:显示索引使用情况,默认 0(关闭);

actions:打印计划中各个步骤的详细信息,默认 0(关闭);

json:以 JSON 格式打印执行计划的详细信息,默认 0(关闭);

23.6版本/24.3版本

ck-test :) explain plan header=1,actions =1  select * replace ('LOL' as name) from students where name = 'Leo';

EXPLAIN header = 1, actions = 1
SELECT * REPLACE 'LOL' AS name
FROM students
WHERE name = 'Leo'

Query id: d9baf4a5-102e-4c28-b04f-c467fe44c11b

┌─explain──────────────────────────────────────────┐
│ Expression ((Projection + Before ORDER BY))      │
│ Header: id UInt32                                │
│         name String                              │
│         age UInt8                                │
│ Actions: INPUT :: 0 -> id UInt32 : 0             │
│          INPUT :: 1 -> age UInt8 : 1             │
│          COLUMN Const(String) -> name String : 2 │
│ Positions: 0 2 1                                 │
│   Filter (WHERE)                                 │
│   Header: id UInt32                              │
│           age UInt8                              │
│   Filter column: 0 (removed)                     │
│   Actions: INPUT :: 0 -> id UInt32 : 0           │
│            INPUT :: 1 -> age UInt8 : 1           │
│            COLUMN Const(UInt8) -> 0 UInt8 : 2    │
│   Positions: 0 1 2                               │
│     ReadFromMergeTree (default.students)         │
│     Header: id UInt32                            │
│             age UInt8                            │
│     ReadType: Default                            │
└──────────────────────────────────────────────────┘

20 rows in set. Elapsed: 0.002 sec. 

ck-test :) select * from students;

SELECT *
FROM students

Query id: d60b6fbf-fb18-4e9f-b909-862c0adfdce0

┌─id─┬─name─┬─age─┐
│  1 │ Leo  │  18 │
└────┴──────┴─────┘

1 row in set. Elapsed: 0.002 sec.

上面是旧版 的详细计划,我们来看看新版 24.3

localhost :) explain plan  header=1,actions =1  select * replace ('LOL' as name) from students where name = 'Leo';

EXPLAIN header = 1, actions = 1
SELECT * REPLACE 'LOL' AS name
FROM students
WHERE name = 'Leo'

Query id: 3e0e03cc-eb8c-4e5b-9a15-f1560be77bf4

    ┌─explain────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
 1. │ Expression ((Project names + Projection))                                                                              │
 2. │ Header: id UInt32                                                                                                      │
 3. │         name String                                                                                                    │
 4. │         age UInt8                                                                                                      │
 5. │ Actions: INPUT : 0 -> __table1.id UInt32 : 0                                                                           │
 6. │          INPUT : 1 -> __table1.age UInt8 : 1                                                                           │
 7. │          COLUMN Const(String) -> name String : 2                                                                       │
 8. │          ALIAS __table1.id :: 0 -> id UInt32 : 3                                                                       │
 9. │          ALIAS __table1.age :: 1 -> age UInt8 : 0                                                                      │
10. │ Positions: 3 2 0                                                                                                       │
11. │   Expression                                                                                                           │
12. │   Header: __table1.id UInt32                                                                                           │
13. │           __table1.age UInt8                                                                                           │
14. │   Actions: INPUT : 0 -> id UInt32 : 0                                                                                  │
15. │            INPUT : 1 -> age UInt8 : 1                                                                                  │
16. │            INPUT :: 2 -> name String : 2                                                                               │
17. │            ALIAS id :: 0 -> __table1.id UInt32 : 3                                                                     │
18. │            ALIAS age :: 1 -> __table1.age UInt8 : 0                                                                    │
19. │   Positions: 3 0                                                                                                       │
20. │     ReadFromMergeTree (default.students)                                                                               │
21. │     Header: name String                                                                                                │
22. │             id UInt32                                                                                                  │
23. │             age UInt8                                                                                                  │
24. │     ReadType: Default                                                                                                  │
25. │     Parts: 1                                                                                                           │
26. │     Granules: 1                                                                                                        │
27. │     Prewhere info                                                                                                      │
28. │     Need filter: 1                                                                                                     │
29. │       Prewhere filter                                                                                                  │
30. │       Prewhere filter column: equals(__table1.name, 'Leo'_String) (removed)                                            │
31. │       Actions: INPUT : 0 -> name String : 0                                                                            │
32. │                COLUMN Const(String) -> 'Leo'_String String : 1                                                         │
33. │                ALIAS name : 0 -> __table1.name String : 2                                                              │
34. │                FUNCTION equals(__table1.name :: 2, 'Leo'_String :: 1) -> equals(__table1.name, 'Leo'_String) UInt8 : 3 │
35. │       Positions: 0 3                                                                                                   │
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

35 rows in set. Elapsed: 0.002 sec. 

明显发现 where 在24.3 的版本ReadFromMergeTree (default.students) (读取阶段)就已经执行了,就不会向23.6版本,一样造成歧义。

以上是作者在实际情况中发现的一点,在官方文档中并没有找到相关的修复说明,有人找到的话,望分享~~ 有不足之处,请指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值