数据库内核月报

数据库内核月报 - 2025 / 12

PolarDB Mysql · 新功能特性 · groupby/orderby消除

Author: 陈江(恬泰)

前提条件

集群版本需为PolarDB MySQL引擎8.0版本,Revision version为8.0.2.2.33及以上

您可以通过查询版本号确认集群版本。

背景信息

在 SQL 查询执行过程中,groupby 算子通常通过排序或哈希去重实现,带来显著的 CPU 和内存开销。然而,在某些情况下,即使未显式去重,查询结果也天然具有唯一性(如主键关联、函数依赖等)。 本优化功能利用 函数依赖(Functional Dependency),在查询优化阶段识别出 groupby列的值已经唯一,自动消除冗余的 groupby算子,从而提升执行效率,降低资源消耗。

原理

使用方法

参数名称 级别 描述
groupby_elimination_mode Global、Session 取值范围:- ON:开启该功能- REPLICA_ON(默认值):只在RO节点开启该功能- OFF: 关闭该功能
orderby_elimination_mode Global、Session 取值范围:- ON:开启该功能- REPLICA_ON(默认值):只在RO节点开启该功能- OFF: 关闭该功能

适用范围

优化场景示例

SELECT a, b, 1, a + b FROM t1 WHERE a = 1 AND b = 1 group by a, b, 1, a + b;
=>
SELECT a, b, 1, a + b FROM t1 WHERE a = 1 AND b = 1 limit 1;
##c_custkey是主键,决定其他列
c_custkey->{c_name, c_acctbal, c_phone,c_address, c_comment,c_nationkey}
## n_nationkey是主键,决定其他列
n_nationkey->n_name
因c_nationkey = n_nationkey,他们相互决定,所以有c_nationkey->n_nationkey
## fd具有传导性c_custkey->c_nationkey, c_nationkey->n_nationkey所以有
c_custkey->n_nationkey
##最终 c_custkey->{c_name, c_acctbal, c_phone,c_address, c_comment,n_nationkey},groupby中的这些列都可以消除
SELECT c_custkey, c_name
	, sum(l_extendedprice * (1 - l_discount)) AS revenue
	, c_acctbal, n_name, c_address, c_phone, c_comment
FROM customer, orders, lineitem, nation
WHERE c_custkey = o_custkey
	AND l_orderkey = o_orderkey
	AND o_orderdate >= '1994-09-01'
	AND o_orderdate < date_add('1994-09-01', INTERVAL '3' MONTH)
	AND l_returnflag = 'R'
	AND c_nationkey = n_nationkey
GROUP BY c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment
ORDER BY revenue DESC
LIMIT 20;
===》
SELECT c_custkey, c_name
	, sum(l_extendedprice * (1 - l_discount)) AS revenue
	, c_acctbal, n_name, c_address, c_phone, c_comment
FROM customer, orders, lineitem, nation
WHERE c_custkey = o_custkey
	AND l_orderkey = o_orderkey
	AND o_orderdate >= '1994-09-01'
	AND o_orderdate < date_add('1994-09-01', INTERVAL '3' MONTH)
	AND l_returnflag = 'R'
	AND c_nationkey = n_nationkey
GROUP BY c_custkey
ORDER BY revenue DESC
LIMIT 20;

性能收益

以上例tpch 100G数据集为例, 开启groupby消除 Q10 性能提升29%。

  开启GB消除(单位:秒) 不开启(单位:秒) 提升
imci 1DOP 48 68 0.29
imci 32DOP 1.9 2.6 0.27

性能对比

核心实现

CREATE TABLE `t1` (a varchar(1));
insert into t1 values('a'), ('A');

mysql> select a, hex(a) from t1;
+------+--------+
| a    | hex(a) |
+------+--------+
| A    | 41     |
| a    | 61     |
+------+--------+
mysql> select a, hex(a) from t1 group by a;
+------+--------+
| a    | hex(a) |
+------+--------+
| a    | 61     |
+------+--------+

在strict sql_mode下,使用utf8mb4_0900_ai_ci比较’a’, ‘A’认为是相等的,所以’a’,’A’被认为是一组,但分别对应了两个HEX值,但这条带groupby的sql能通过ONLY_FULL_GROUP_BY检查,这是个bug。 polardb要完全兼容mysql,就算是bug,也要保证行为一模一样 所以如下sql虽然在关系代数中可以无脑消掉GB,但在mysql codebase中要保留,确保跟mysql兼容

select a, hex(a) from t1 group by a, hex(a)
可改写成==>select a, hex(a) from t1 group by a
//在mysql中不要做改写

构建fd graph

唯一性来源

常量性来源

使用fd graph进行唯一性测试

测试{init_fdset}->target是否成立,用函数bool fd_exists(init_fdset, target)表示 我们有输入fd集合init_fdset,通过图的连通性(fd就是图的边)不断扩充fd集合,当图不再发生变化,判断target节点是否在最终的fd集合中,如果在说明{init_fdset}->target成立。参考图染色算法,每轮染色后判断是否有新染色节点,没有的话可退出循环。

Corner case