应直接通过执行计划和运行时指标定位SQL性能瓶颈,而非依赖断点调试;必须使用EXPLAIN ANALYZE获取真实耗时与行数,结合系统视图统计、规避参数嗅探、禁用游标输出,紧盯rows_examined等硬指标。
直接看执行计划和运行时指标,别依赖断点单步——多数数据库(尤其是MySQL)不支持真断点调试,而SQL性能瓶颈几乎从不在“哪一行卡住”,而在“哪一步扫了10万行”。
EXPLAIN ANALYZE 替代单步执行(PostgreSQL / MySQL 8.0+)存储过程内部的SQL语句不会自动暴露执行细节,必须把关键查询抽出来单独分析。不能只看 EXPLAIN,要带实际执行耗时的 EXPLAIN ANALYZE。
EXPLAIN ANALYZE SELECT * FROM your_function(...),它会显示每个子查询的真实耗时、行数、是否溢出磁盘performance_schema,再用 EXPLAIN FORMAT=JSON 查看 execution_time 和 rows_examined
EXPLAIN ANALYZE 只能穿透一层,深层逻辑需手动拆解pg_stat_user_functions 或 sys.dm_exec_procedure_stats(PostgreSQL / SQL Server)这些系统视图记录的是真实调用后的聚合统计,比“猜哪里慢”可靠得多。
SELECT * FROM pg_stat_user_functions WHERE calls > 10 ORDER BY total_time DESC LIMIT 5,立刻看到最耗时的函数SELECT object_name(object_id), execution_count, total_logical_reads, total_elapsed_time FROM sys.dm_exec_procedure_stats WHERE database_id = DB_ID(),重点关注 total_logical_reads / execution_count 偏高的过程同一个存储过程,传入不同参数时性能差10倍?大概率是执行计划被缓存后没适配新参数分布。
WITH RECOMPILE 强制每次重编译,或用 OPTIMIZE FOR 提示指定典型值EXECUTE 'SELECT ...' USING param 可绕过缓存,但要注意SQL注入风险看到有人在存储过程中加 SELECT 'debug', @var 或循环打印中间结果?这不仅污染输出,还可能让原本 200ms 的过程变成 2s——尤其在高并发下。
INSERT INTO debug_log VALUES (...)),且仅在开发环境开启开关rows_examined 和 temp_tables_created 这类硬指标,不是“变量值对不对”SELECT 查看,而不是边算边输出复杂存储过程的性能瓶颈,往往藏在“看似无害”的连接顺序、隐式类型转换、或一个没覆盖的 ORDER BY 字段里——执行计划不会说谎,但得你亲手把它拖出来看清楚。