×
技术社区 >  技术博客 >  实测验证|OceanBase 修改列注释也会刷新 SQL 执行计划缓存

实测验证|OceanBase 修改列注释也会刷新 SQL 执行计划缓存

日常运维中,大家普遍认为加字段、删索引、修改字段类型这类实质性表结构变更才会触发 Plan Cache 刷新;仅修改列注释属于纯备注文本调整,不会影响 SQL 执行逻辑,大概率不会刷新执行计划。

今天我们通过一套完整复现实验,推翻固有认知:OceanBase MySQL 租户下,ALTER TABLE MODIFY COLUMN COMMENT 修改列注释,同样会刷新该表关联 SQL 的执行计划缓存,生产运维务必注意该隐性性能损耗。

一、实验环境与前置准备

本次实验在 OceanBase MySQL 租户 test 库中进行,目的是验证“修改列注释”操作是否会刷新该表相关 SQL 的执行计划。

实验对象表为 t_plan_test,建表语句如下:

CREATE TABLE t_plan_test (
  id BIGINT NOT NULL PRIMARY KEY,
  c1 BIGINT NOT NULL,
  c2 VARCHAR(100) DEFAULT NULL COMMENT 'comment_v1',
  c3 DATETIME DEFAULT NULL,
  KEY idx_t_plan_test_c1 (c1)
);

插入 10 条测试数据后,先执行如下语句清空计划缓存:

ALTER SYSTEM FLUSH PLAN CACHE GLOBAL;

二、阶段 1:无任何 DDL,SQL 稳定复用缓存计划

随后连续 3 次执行目标 SQL:

SELECT * FROM t_plan_test WHERE c1 = 1001;

执行结果如下,3 次返回结果一致:

MySQL [test]> SELECT * FROM t_plan_test WHERE c1 = 1001;
+----+------+------+---------------------+
| id | c1   | c2   | c3                  |
+----+------+------+---------------------+
|  1 | 1001 | a    | 2026-05-06 16:19:30 |
|  4 | 1001 | d    | 2026-05-06 16:19:30 |
|  6 | 1001 | f    | 2026-05-06 16:19:30 |
|  8 | 1001 | h    | 2026-05-06 16:19:30 |
| 10 | 1001 | j    | 2026-05-06 16:19:30 |
+----+------+------+---------------------+
5 rows in set

同时通过EXPLAIN查看执行计划,可以看到该 SQL 走的是索引idx_t_plan_test_c1

MySQL [test]> explain SELECT * FROM t_plan_test WHERE c1 = 1001;
+--------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                   |
+--------------------------------------------------------------------------------------------------------------+
| ===========================================================================                                  |
| |ID|OPERATOR        |NAME                           |EST.ROWS|EST.TIME(us)|                                  |
| ---------------------------------------------------------------------------                                  |
| |0 |TABLE RANGE SCAN|t_plan_test(idx_t_plan_test_c1)|5       |18          |                                  |
| ===========================================================================                                  |
| Outputs & filters:                                                                                           |
| -------------------------------------                                                                        |
|   0 - output([t_plan_test.id], [t_plan_test.c1], [t_plan_test.c2], [t_plan_test.c3]), filter(nil), rowset=16 |
|       access([t_plan_test.id], [t_plan_test.c1], [t_plan_test.c2], [t_plan_test.c3]), partitions(p0)         |
|       is_index_back=true, is_global_index=false,                                                             |
|       range_key([t_plan_test.c1], [t_plan_test.id]), range(1001,MIN ; 1001,MAX),                             |
|       range_cond([t_plan_test.c1 = 1001])                                                                    |
+--------------------------------------------------------------------------------------------------------------+

之后查询计划缓存视图。由于 OceanBase 会对 SQL 做参数化,因此视图中记录的语句并不是 c1 = 1001,而是 c1 = ?。实际查询结果如下:

MySQL [test]> SELECT tenant_id, svr_ip, svr_port, sql_id, plan_id, plan_hash,
    -> first_load_time, schema_version, hit_count, executions, statement
    -> FROM oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT
    -> WHERE statement LIKE 'SELECT%t_plan_test%';
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
| tenant_id | svr_ip     | svr_port | sql_id                           | plan_id | plan_hash           | first_load_time            | schema_version   | hit_count | executions | statement                              |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
|      1014 | 20.8.XX.XX |     2882 | DD2A9B8AC9A2E9998ACEB39032474DC8 |   11304 | 9462375352054846661 | 2026-05-06 16:19:44.761531 | 1778055563385160 |         2 |          3 | SELECT * FROM t_plan_test WHERE c1 = ? |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
1 row in set

在不做任何 DDL 变更的情况下,再执行 2 次相同 SQL,然后再次查询计划缓存,结果如下:

MySQL [test]> SELECT tenant_id, svr_ip, svr_port, sql_id, plan_id, plan_hash,
    -> first_load_time, schema_version, hit_count, executions, statement
    -> FROM oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT
    -> WHERE statement LIKE 'SELECT%t_plan_test%';
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
| tenant_id | svr_ip     | svr_port | sql_id                           | plan_id | plan_hash           | first_load_time            | schema_version   | hit_count | executions | statement                              |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
|      1014 | 20.8.XX.XX |     2882 | DD2A9B8AC9A2E9998ACEB39032474DC8 |   11304 | 9462375352054846661 | 2026-05-06 16:19:44.761531 | 1778055563385160 |         4 |          5 | SELECT * FROM t_plan_test WHERE c1 = ? |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
1 row in set

可以看到,sql_id、plan_id、plan_hash、first_load_time、schema_version都没有变化,只是hit_count从 2 增加到 4,executions从 3 增加到 5,说明在没有表结构变化的情况下,该 SQL 持续复用原执行计划,没有发生刷新。

三、阶段 2:仅修改列注释,观测计划缓存变化

接着执行修改列注释语句:

ALTER TABLE t_plan_test
MODIFY COLUMN c2 VARCHAR(100) DEFAULT NULL COMMENT 'comment_v2';

执行成功后,通过SHOW CREATE TABLE 确认列注释已经发生变化,结果如下:

MySQL [test]> SHOW CREATE TABLE t_plan_test;
+-------------+------------------------------------------------------------------+
| Table       | Create Table                                                     |
+-------------+------------------------------------------------------------------+
| t_plan_test | CREATE TABLE `t_plan_test` (
  `id` bigint(20) NOT NULL,
  `c1` bigint(20) NOT NULL,
  `c2` varchar(100) DEFAULT NULL COMMENT 'comment_v2',
  `c3` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_t_plan_test_c1` (`c1`) BLOCK_SIZE 16384 LOCAL
) ...
+-------------+------------------------------------------------------------------+
1 row in set

随后再次执行 2 次目标 SQL,并查询计划缓存,结果如下:

MySQL [test]> SELECT tenant_id, svr_ip, svr_port, sql_id, plan_id, plan_hash,
    -> first_load_time, schema_version, hit_count, executions, statement
    -> FROM oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT
    -> WHERE statement LIKE 'SELECT%t_plan_test%';
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
| tenant_id | svr_ip     | svr_port | sql_id                           | plan_id | plan_hash           | first_load_time            | schema_version   | hit_count | executions | statement                              |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
|      1014 | 20.8.XX.XX |     2882 | DD2A9B8AC9A2E9998ACEB39032474DC8 |   11403 | 9462375352054846661 | 2026-05-06 16:21:02.846497 | 1778055649996008 |         1 |          2 | SELECT * FROM t_plan_test WHERE c1 = ? |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
1 row in set

与修改前相比,这里的 sql_id 保持不变,仍为 DD2A9B8AC9A2E9998ACEB39032474DC8,但 plan_id 已经由 11304 变为 11403,first_load_time 由 2026-05-06 16:19:44.761531 变为 2026-05-06 16:21:02.846497,schema_version 也从 1778055563385160 变为 1778055649996008,而 plan_hash 仍保持为 9462375352054846661。

这说明修改列注释后,目标 SQL 的执行计划确实发生了刷新,但刷新前后执行计划形状没有变化。

四、阶段 3:标准结构变更(新增列)对照验证实验

为进一步验证该观察方式本身有效,实验中又执行了一个明确的表结构变更操作:

ALTER TABLE t_plan_test ADD COLUMN c4 BIGINT DEFAULT NULL;

之后再次执行相同 SQL,并查询计划缓存,结果如下:

MySQL [test]> SELECT tenant_id, svr_ip, svr_port, sql_id, plan_id, plan_hash,
    -> first_load_time, schema_version, hit_count, executions, statement
    -> FROM oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT
    -> WHERE statement LIKE 'SELECT%t_plan_test%';
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
| tenant_id | svr_ip     | svr_port | sql_id                           | plan_id | plan_hash           | first_load_time            | schema_version   | hit_count | executions | statement                              |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
|      1014 | 20.8.XX.XX |     2882 | DD2A9B8AC9A2E9998ACEB39032474DC8 |   11405 | 9462375352054846661 | 2026-05-06 16:21:22.235974 | 1778055676741792 |         1 |          2 | SELECT * FROM t_plan_test WHERE c1 = ? |
+-----------+------------+----------+----------------------------------+---------+---------------------+----------------------------+------------------+-----------+------------+----------------------------------------+
1 row in set

可以看到,在执行 ADD COLUMN 之后,plan_id又从 11403 变为 11405,first_load_timeschema_version也再次更新,说明本实验使用的判定方法能够有效识别 DDL 引起的执行计划刷新,因此实验结论可信。

实验结论

综合本次实验结果可以得出结论:在 OceanBase MySQL 租户中,执行

ALTER TABLE ... MODIFY COLUMN ... COMMENT ...

之后,会触发该表相关 SQL 的执行计划刷新。

该结论的直接证据是:修改列注释前后,目标 SQL 的sql_id保持不变,但plan_idfirst_load_timeschema_version 发生变化。同时,plan_hash 保持不变,说明刷新前后执行计划形状一致。

精选推荐