关于列裁剪的疑问

为提高效率,请提供以下信息,问题描述清晰能够更快得到解决:
【 TiDB 使用环境】
TiDB v4.0.13测试环境

【概述】 场景 + 问题概述
最近在看SQL优化相关的文档,发现有列裁剪这一优化
假设表 t 里面有 a b c d 四列,执行如下语句:

select a from t where b > 5

在该查询的过程中,t 表实际上只有 a, b 两列会被用到,而 c, d 的数据则显得多余。对应到该语句的查询计划,Selection 算子会用到 b 列,下面接着的 DataSource 算子会用到 a, b 两列,而剩下 c, d 两列则都可以裁剪掉,DataSource 算子在读数据时不需要将它们读进来。

出于上述考量,TiDB 会在逻辑优化阶段进行自上而下的扫描,裁剪不需要的列,减少资源浪费。该扫描过程称作 “列裁剪”,对应逻辑优化规则中的 columnPruner 。如果要关闭这个规则,可以在参照优化规则及表达式下推的黑名单中的关闭方法。

【背景】 做过哪些操作
关闭列裁剪前的执行计划

(root@127.0.0.1:4000) [tidb_test] show create table tab_tidb;
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                                                                                                                                                                                                                                                                   |
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tab_tidb | CREATE TABLE `tab_tidb` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '',
  `age` int(11) NOT NULL DEFAULT '0',
  `version` varchar(20) NOT NULL DEFAULT '',
  `status` int(11) DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `idx_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=150002 |
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
(root@127.0.0.1:4000) [tidb_test] explain select name from tab_tidb where id >2;
+--------------------------+---------+-----------+----------------+----------------------------------+
| id                       | estRows | task      | access object  | operator info                    |
+--------------------------+---------+-----------+----------------+----------------------------------+
| Projection_4             | 2.00    | root      |                | tidb_test.tab_tidb.name          |
| └─TableReader_6          | 2.00    | root      |                | data:TableRangeScan_5            |
|   └─TableRangeScan_5     | 2.00    | cop[tikv] | table:tab_tidb | range:(2,+inf], keep order:false |
+--------------------------+---------+-----------+----------------+----------------------------------+
3 rows in set (0.04 sec)

关闭列裁剪

(root@127.0.0.1:4000) [tidb_test] select * from  mysql.opt_rule_blacklist;
Empty set (0.01 sec)

(root@127.0.0.1:4000) [tidb_test] INSERT INTO mysql.opt_rule_blacklist VALUES("column_prune");
Query OK, 1 row affected (0.07 sec)

(root@127.0.0.1:4000) [tidb_test] ADMIN reload opt_rule_blacklist;
Query OK, 0 rows affected (0.01 sec)

(root@127.0.0.1:4000) [tidb_test] select * from  mysql.opt_rule_blacklist;
+--------------+
| name         |
+--------------+
| column_prune |
+--------------+
1 row in set (0.01 sec)

关闭列裁剪后的执行计划

(root@127.0.0.1:4000) [tidb_test] explain select name from tab_tidb where id >2;
+--------------------------+---------+-----------+----------------+----------------------------------+
| id                       | estRows | task      | access object  | operator info                    |
+--------------------------+---------+-----------+----------------+----------------------------------+
| Projection_4             | 2.00    | root      |                | tidb_test.tab_tidb.name          |
| └─TableReader_6          | 2.00    | root      |                | data:TableRangeScan_5            |
|   └─TableRangeScan_5     | 2.00    | cop[tikv] | table:tab_tidb | range:(2,+inf], keep order:false |
+--------------------------+---------+-----------+----------------+----------------------------------+
3 rows in set (0.01 sec)

发现执行计划并木有变化,难道是TiDB内部的优化,从执行计划上看不出来?

执行计划应该显示不了这么细,列裁剪就是读出数据后把不需要的列就不向上层返回了,减少处理的数据量,最终的输出结果还是按照SQL实际要求输出。

是的,从执行计划上看不出来。
因为你只 select 了 name 这一列,所以这个 Projection 从一开始就只有 name 这一列。
但是下面的 Table Reader 的话,如果你不打开列裁剪的话,会把整张表的列都读上来,但是这个没在执行计划里面展示。
感兴趣的话,这个可以在 DoOptimize() 函数里面打断点看。

此话题已在最后回复的 1 分钟后被自动关闭。不再允许新回复。