当查询仅从包含大量列的派生表或视图中选取少数几列时,可能会因读取和处理不必要的数据而导致性能下降。此问题在处理宽表或复用大而全的通用视图时尤为突出。PolarDB MySQL版的列裁剪(Column Pruning)功能可自动优化此类查询。它在查询解析阶段识别并移除派生表或视图中未被最终引用的列,从而显著减少数据扫描量、网络传输和内存消耗,降低查询延迟,提升系统吞吐。
适用范围
产品系列:集群版、标准版。
内核版本:MySQL 8.0.2,且修订版本需为8.0.2.2.31.1及以上版本。
开启列裁剪
通过设置loose_derived_table_pruning_mode参数来控制此优化功能的行为。
PolarDB集群参数在控制台与会话中修改方式存在差异,详细区别如下:
在PolarDB控制台上修改:
兼容性说明:部分集群参数在PolarDB控制台上均已添加MySQL配置文件的兼容性前缀loose_。
操作方法:找到并修改这些带
loose_前缀的参数。
在数据库会话中修改(使用命令行或客户端):
操作方法:当您连接到数据库,使用
SET命令修改参数时,请去掉loose_前缀,直接使用参数的原始名称进行修改。
参数名称 | 级别 | 描述 |
| Global/Session | 控制该功能的主开关。取值范围如下:
|
工作原理与示例
列裁剪优化的核心是查询改写。在查询的逻辑优化阶段,优化器会分析整个查询语句,识别出派生表或视图中未被最终SELECT列表、WHERE条件、JOIN条件等引用的列。若某列是多余的,优化器会重写内部查询,从源头避免读取和处理该列的数据,从而减少I/O和CPU消耗。
示例1:优化派生表查询
此示例展示了列裁剪如何优化对派生表的查询。
-- 优化前
SELECT c1 FROM (SELECT c1 FROM (SELECT c1, c2 FROM t1 GROUP BY c1, c2) v) t;
-- 优化后
SELECT c1 FROM (SELECT c1 FROM t1 GROUP BY c1, c2) v准备测试数据:在数据库中创建一张包含多个列的表
t1。CREATE TABLE t1 (id INT PRIMARY KEY, c1 INT, c2 INT, c3 VARCHAR(100)); INSERT INTO t1 VALUES (1, 10, 100, 'data'), (2, 20, 200, 'data');关闭优化进行查询:首先,在会话中关闭列裁剪功能,以观察优化前的执行计划。
SET derived_table_pruning_mode = 'OFF'; EXPLAIN SELECT c1 FROM (SELECT c1 FROM (SELECT c1, c2 FROM t1 GROUP BY c1, c2) v) t;SHOW warnings; +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | /* select#1 */ select `v`.`c1` AS `c1` from (/* select#3 */ select `testdb`.`t1`.`c1` AS `c1`,`testdb`.`t1`.`c2` AS `c2` from `testdb`.`t1` group by `testdb`.`t1`.`c1`,`testdb`.`t1`.`c2`) `v` | +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+开启优化进行查询:现在,在会话中开启列裁剪功能,并执行相同的查询。
SET derived_table_pruning_mode = 'ON'; EXPLAIN SELECT c1 FROM (SELECT c1 FROM (SELECT c1, c2 FROM t1 GROUP BY c1, c2) v) t;SHOW warnings; +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | /* select#1 */ select `v`.`c1` AS `c1` from (/* select#3 */ select `testdb`.`t1`.`c1` AS `c1` from `testdb`.`t1` group by `testdb`.`t1`.`c1`,`testdb`.`t1`.`c2`) `v` | +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+执行计划解读:优化后的执行计划发生了显著变化。优化器识别到外部查询仅需
c1列,因此直接重写了查询。
示例2:优化视图查询
列裁剪对视图的优化与派生表类似,能够避免不必要的计算。
CREATE VIEW v1 AS SELECT COUNT(*) AS a, (SELECT a FROM t2 WHERE a=FLOOR(COUNT(t1.a)/2)) AS s FROM t1;
-- 优化前
SELECT a FROM v1;
-- 优化后
SELECT COUNT(*) AS a FROM t1;优化限制
只有在保证查询结果与原始SQL语义完全等价的前提下,列裁剪优化才会触发。当派生表或视图中看似未被引用的列实际参与了以下运算时,该列不会被裁剪:
被用于
ORDER BY、GROUP BY、HAVING或DISTINCT子句。被用于窗口函数(Window Function)的分区键(
PARTITION BY)或排序键(ORDER BY)。如果被裁剪的列是基于一个非确定性函数(如
RAND()、UUID())生成的,该函数将不会被执行,从而避免了不必要的计算开销。此为优化效果,非限制。