日常运维中,大家普遍认为 加字段、删索引、修改字段类型这类实质性表结构变更才会触发 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;
随后连续 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 持续复用原执行计划,没有发生刷新。
接着执行修改列注释语句:
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 的执行计划确实发生了刷新,但刷新前后执行计划形状没有变化。
为进一步验证该观察方式本身有效,实验中又执行了一个明确的表结构变更操作:
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_time和
schema_version也再次更新,说明本实验使用的判定方法能够有效识别 DDL 引起的执行计划刷新,因此实验结论可信。
综合本次实验结果可以得出结论:在 OceanBase MySQL 租户中,执行
ALTER TABLE ... MODIFY COLUMN ... COMMENT ...
之后,会触发该表相关 SQL 的执行计划刷新。
该结论的直接证据是:修改列注释前后,目标 SQL 的
sql_id保持不变,但
plan_id、
first_load_time 和
schema_version 发生变化。同时,
plan_hash 保持不变,说明刷新前后执行计划形状一致。
如果你在实际操作中遇到问题,可以在评论区留言交流。后续我们会持续分享更多运维干货,记得 关注不迷路 ,下次见~
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047467/viewspace-3173977/ ,如需转载,请注明出处,否则将追究法律责任。