Analyzer
已知不兼容性
在 ClickHouse 版本 24.3
中,新的查询分析器默认启用。尽管修复了大量错误并引入了新的优化,但它也为 ClickHouse 的行为引入了一些重大更改。请阅读以下更改,以确定如何为新的分析器重写您的查询。
无效查询不再被优化
之前的查询规划基础设施在查询验证步骤之前应用 AST 级别的优化。优化可以重写初始查询,使其变为有效并可以执行。
在新的分析器中,查询验证发生在优化步骤之前。这意味着以前可能执行的无效查询现在不受支持。在这种情况下,必须手动修复查询。
示例 1
SELECT number
FROM numbers(1)
GROUP BY toString(number)
以下查询在投影列表中使用了列 number
,而聚合后只有 toString(number)
可用。在旧的分析器中,GROUP BY toString(number)
被优化为 GROUP BY number
,从而使查询有效。
示例 2
SELECT
number % 2 AS n,
sum(number)
FROM numbers(10)
GROUP BY n
HAVING number > 5
此查询中也出现同样的问题:列 number
在与另一个键聚合后使用。之前的查询分析器通过将 number > 5
过滤器从 HAVING
子句移动到 WHERE
子句来修复此查询。
要修复查询,您应该将所有适用于非聚合列的条件移动到 WHERE
部分,以符合标准 SQL 语法
SELECT
number % 2 AS n,
sum(number)
FROM numbers(10)
WHERE number > 5
GROUP BY n
使用无效查询创建 VIEW
新的分析器始终执行类型检查。以前,可以创建一个带有无效 SELECT
查询的 VIEW
。然后在第一次 SELECT
或 INSERT
(在 MATERIALIZED VIEW
的情况下)期间会失败。
现在,不再可能创建这样的 VIEW
。
示例
CREATE TABLE source (data String) ENGINE=MergeTree ORDER BY tuple();
CREATE VIEW some_view
AS SELECT JSONExtract(data, 'test', 'DateTime64(3)')
FROM source;
`JOIN` 子句的已知不兼容性
使用投影中的列进行 Join
默认情况下,来自 SELECT
列表的别名不能用作 JOIN USING
键。
一个新的设置 `analyzer_compatibility_join_using_top_level_identifier`,启用后,会更改 `JOIN USING` 的行为,使其优先根据 SELECT
查询的投影列表中的表达式解析标识符,而不是直接使用左表的列。
示例
SELECT a + 1 AS b, t2.s
FROM Values('a UInt64, b UInt64', (1, 1)) AS t1
JOIN Values('b UInt64, s String', (1, 'one'), (2, 'two')) t2
USING (b);
当 `analyzer_compatibility_join_using_top_level_identifier` 设置为 `true` 时,连接条件被解释为 `t1.a + 1 = t2.b`,与早期版本的行为一致。因此,结果将是 `2, 'two'`。当设置是 `false` 时,连接条件默认为 `t1.b = t2.b`,查询将返回 `2, 'one'`。如果 `b` 在 `t1` 中不存在,查询将失败并显示错误。
`JOIN USING` 和 `ALIAS`/`MATERIALIZED` 列的行为变更
在新的分析器中,在涉及 `ALIAS` 或 `MATERIALIZED` 列的 `JOIN USING` 查询中使用 `*` 默认会将这些列包含在结果集中。
示例
CREATE TABLE t1 (id UInt64, payload ALIAS sipHash64(id)) ENGINE = MergeTree ORDER BY id;
INSERT INTO t1 VALUES (1), (2);
CREATE TABLE t2 (id UInt64, payload ALIAS sipHash64(id)) ENGINE = MergeTree ORDER BY id;
INSERT INTO t2 VALUES (2), (3);
SELECT * FROM t1
FULL JOIN t2 USING (payload);
在新的分析器中,此查询的结果将包含 `payload` 列以及来自两个表的 `id`。相比之下,之前的分析器仅在启用特定设置(`asterisk_include_alias_columns` 或 `asterisk_include_materialized_columns`)时才包含这些 `ALIAS` 列,并且列可能以不同的顺序出现。
为了确保一致和预期的结果,特别是在将旧查询迁移到新分析器时,建议在 `SELECT` 子句中显式指定列,而不是使用 `*`。
`USING` 子句中列的类型修饰符处理
在新版本的分析器中,用于确定 `USING` 子句中指定的列的公共超类型的规则已标准化,以产生更可预测的结果,尤其是在处理 `LowCardinality` 和 `Nullable` 等类型修饰符时。
-
`LowCardinality(T)` 和 `T`:当类型为 `LowCardinality(T)` 的列与类型为 `T` 的列连接时,结果公共超类型将为 `T`,有效地丢弃 `LowCardinality` 修饰符。
-
`Nullable(T)` 和 `T`:当类型为 `Nullable(T)` 的列与类型为 `T` 的列连接时,结果公共超类型将为 `Nullable(T)`,确保保留可空属性。
示例
SELECT id, toTypeName(id) FROM Values('id LowCardinality(String)', ('a')) AS t1
FULL OUTER JOIN Values('id String', ('b')) AS t2
USING (id);
在此查询中,`id` 的公共超类型被确定为 `String`,丢弃了来自 `t1` 的 `LowCardinality` 修饰符。
投影列名更改
在投影名称计算期间,别名不会被替换。
SELECT
1 + 1 AS x,
x + 1
SETTINGS enable_analyzer = 0
FORMAT PrettyCompact
┌─x─┬─plus(plus(1, 1), 1)─┐
1. │ 2 │ 3 │
└───┴─────────────────────┘
SELECT
1 + 1 AS x,
x + 1
SETTINGS enable_analyzer = 1
FORMAT PrettyCompact
┌─x─┬─plus(x, 1)─┐
1. │ 2 │ 3 │
└───┴────────────┘
不兼容的函数参数类型
在新的分析器中,类型推断发生在初始查询分析期间。此更改意味着类型检查在短路求值之前完成;因此,`if` 函数参数必须始终具有公共超类型。
示例
以下查询失败,并显示错误消息:`There is no supertype for types Array(UInt8), String because some of them are Array and some of them are not`
SELECT toTypeName(if(0, [2, 3, 4], 'String'))
异构集群
新的分析器显著更改了集群中服务器之间的通信协议。因此,无法在 `enable_analyzer` 设置值不同的服务器上运行分布式查询。
Mutations 由之前的分析器解释
Mutations 仍然使用旧的分析器。这意味着一些新的 ClickHouse SQL 功能不能在 mutations 中使用。例如,`QUALIFY` 子句。状态可以在这里查看。
不支持的功能
新的分析器当前不支持的功能列表
- Annoy 索引。
- Hypothesis 索引。正在开发中 这里。
- 不支持窗口视图。未来没有计划支持它。