MySQL 8.0.16+才支持动态修改成本模型参数,5.7及更早版本不支持;需关闭查询缓存、启用optimizer_trace,设置show_compatibility_56=ON(8.0.23+改用information_schema_stats_expiry=0),更新后执行FLUSH OPTIMIZER_COSTS生效。

MySQL 8.0+ 才支持动态修改成本模型参数
MySQL 5.7 及更早版本(包括 XAMPP 默认 bundled 的 MySQL 5.7.33)**不支持运行时修改成本常量**,server_cost 和 engine_cost 表是只读的——你执行 UPDATE 会报错 ERROR 1294 (HY000): Invalid option。只有 MySQL 8.0.16+ 开始才允许通过 INSERT/UPDATE 修改这些系统表,且需重启服务后生效(不是热加载)。
所以第一步先确认你的 XAMPP 版本带的是哪个 MySQL:
- 打开 XAMPP 控制面板 → 点击 MySQL 行右侧的 Config → 选
my.ini - 在文件顶部或
[mysqld]段落里找version相关注释,或直接进 MySQL 执行:SELECT VERSION();
若结果是 5.7.x,下面所有修改都无效,跳过;若是 8.0.16+,继续。
修改前必须关闭查询缓存并启用 optimizer_trace(调试必需)
成本模型调整效果无法直观感知,必须配合 optimizer_trace 观察执行计划变化。但 XAMPP 自带的 MySQL 5.7+ 默认禁用该功能,且旧版配置里可能残留 query_cache_type = 1,它会干扰优化器行为判断。
实操建议:
- 确保
my.ini的[mysqld]下没有query_cache_type或query_cache_size配置项(删掉或注释) - 添加:
optimizer_trace = "enabled=on,one_line=off" - 添加:
optimizer_trace_max_mem_size = 1048576(防止 trace 截断) - 重启 MySQL 服务
- 连接后执行:
SET optimizer_trace="enabled=on,one_line=off";(会话级开启)
更新 server_cost / engine_cost 表要绕过只读限制
即使 MySQL 8.0+,默认启动下 mysql.server_cost 仍是只读表。必须显式关闭系统变量才能写入:
- 启动 MySQL 前,在
my.ini的[mysqld]下加一行:optimizer_switch = 'derived_merge=off,subquery_to_derived=off'(非必需,但避免衍生表干扰) - 更重要的是加:
show_compatibility_56 = ON(仅限 8.0.16–8.0.22;8.0.23+ 已移除,改用information_schema_stats_expiry = 0) - 重启后,执行:
UPDATE mysql.server_cost SET cost_value = 0.01 WHERE cost_name = 'key_compare_cost'; - 必须跟一句:
FLUSH OPTIMIZER_COSTS;—— 否则新值不载入内存
常见可调参数及典型调低场景:
-
key_compare_cost:从默认0.05改为0.01,让优化器更倾向走索引而非全表扫描(适合高区分度索引) -
row_evaluate_cost:从0.2改为0.05,降低“逐行过滤”成本权重(适合 where 条件简单、CPU 充足的环境) -
disk_temptable_row_cost:从0.5提高到2.0,惩罚磁盘临时表(逼优化器尽量用内存表或改写避免临时表)
验证是否生效不能只看 SELECT,要看 optimizer_trace 输出
改完成本参数后,SELECT * FROM mysql.server_cost; 显示的是新值,但这不代表优化器已采用。真正要看的是某条具体 SQL 的 trace 结果中 cost_for_plan 是否变化。
执行一个带 JOIN 或 ORDER BY 的语句后,查:SELECT * FROM information_schema.OPTIMIZER_TRACE\G
重点检查字段:
-
steps里的"rows_estimation"阶段是否用了新基数 -
"considered_execution_plans"中不同 plan 的"cost"数值是否按你调的参数比例变化 - 最终
"chosen_plan"是否从原来的"using_filesort"变成"using_index"
注意:成本模型只是估算,统计信息不准(比如 Cardinality 偏离真实值)时,再调参数也白搭。务必先执行:ANALYZE TABLE your_table; 更新统计。


















