问题简介
Dashboard中TOP SQL里一直有一条explain format的select语句,任何时间段都存在,call/sec=0.7,寻找其来源。
环境说明
tidb v8.5.4
三节点混合部署
问题详细说明
Dashboard中TOP SQL里一直有一条explain format的select语句,最开始认为可能是代码有bug,但是后面观察其对应的ticdc从库top SQL里也有该SQL,但是ticdc从库时只读的,也无业务连接。
当下怀疑方向及其分析措施如下:
1)上游有不停执行explain语句,导致下游也不停重放--排除
:ticdc只是会同步kv log,不会同步explain语句,且explain format本身的SQL并不会实际执行;
:从库启用general log,也未发现该explain sql的执行记录。
:由于从库有该SQL,基本排除了应用程序的bug,应该就是系统类的问题。
2)top SQL里存在,但对应的“SQL语句分析”没有该SQL“。
:根据top SQL里提供的SQL模板ID到INFORMATION_SCHEMA.CLUSTER_STATEMENTS_SUMMARY表中查询,无该SQL信息。
3)有什么系统表被同步到从库?从库采用的是主库的数据??
解决方案
结论:
这条 SQL 是 TiDB SQL Plan Management(SPM,SQL 计划基线 / Binding)模块的内部受限 SQL,
由 bindinfo.getHintsForSQL() 在加载/创建执行计划基线时发出。
它不是用户/应用发出的 SQL,因此:
出现在 Top SQL:Top SQL 基于 CPU 采样,会采样正在运行的 goroutine 当前 SQL(含内部 SQL)。
不在 Statement Summary(cluster_statement_summary):内部 SQL 默认被排除(tidb_stmt_summary_internal_query=off)。
不在 general log:该函数在 :590-594 显式置 InRestrictedSQL=true,刻意隐藏该内部 EXPLAIN 不被审计/通用日志记录。
下游也出现:上游 mysql.bind_info 的基线被 TiCDC 同步到下游(或下游对同一负载独立做了基线捕获),下游 TiDB 加载这些 binding 时重放同样的内部 EXPLAIN FORMAT='hint'。
下游ticdc出现的原因
EXPLAIN FORMAT='hint' 的触发条件是:TiDB 加载/创建一条 SQL 计划基线(binding)。触发路径:newBinding()(global_handle.go:554)→ prepareHints() → getHintsForSQL() → 内部 EXPLAIN。
下游出现同一 SQL 的两条可能链路(任一成立即可):
mysql.bind_info 被 TiCDC 同步:TiCDC 默认 filter 多为 *.*,会把 mysql 系统表(含 bind_info、stats_*、user 等)的变更一并同步到下游。下游 TiDB 加载这些被同步来的 binding → 重放同样的内部 EXPLAIN。
下游独立做了 SPM 自动捕获:下游承接了与上游相同的业务负载(读副本/双活),若下游也开启了tidb_capture_plan_baselines 或基线演进,会对相同 SELECT 生成 binding → 同样触发内部 EXPLAIN。
验证
1)查看当前是否有绑定
show global bindings;
select * from mysql.bind_info;
2)SPM自动捕获/演进是否开启
> show variables like '%plan_baselines';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| tidb_capture_plan_baselines | OFF |
| tidb_evolve_plan_baselines | OFF |
3)临时打开内部SQL记录,查看statement_summary是否有记录
SET GLOBAL tidb_stmt_summary_internal_query = ON;
根据指定的SQL模版ID可以正常从该表中获取到SQL。




