当前位置:首页 > 问答 > 正文

MySQL报错|远程修复 MySQL Error 3965 ER_WARN_DEPRECATED_FOUND_ROWS 故障处理与解决方法

MySQL报错|远程修复 MySQL Error 3965 ER_WARN_DEPRECATED_FOUND_ROWS 故障处理与解决方法

最新动态:截至2025年8月,MySQL 8.4版本中FOUND_ROWS()函数已被正式标记为废弃特性,许多开发者迁移数据库时意外触发了3965错误警告,这已成为近期社区讨论热点问题之一。

问题现象描述

上周三晚上十点半,我正瘫在沙发上刷短视频,突然企业微信炸出一连串报警——电商平台的订单查询接口集体抽风,虽然系统还在勉强运行,但日志里全是刺眼的警告:

[Warning] [MY-013965] [Server] FOUND_ROWS() is deprecated 
and will be removed in a future release. Consider using 
COUNT(*) instead. Error: 3965

这个报错最烦人的地方在于:它不会直接让服务挂掉,但会在日志里疯狂刷屏,搞得监控系统天天报警,运维同事差点把我工位给拆了。

为什么会出现这个错误

简单来说就是你用了MySQL里一个"过气"的功能,FOUND_ROWS()这函数以前常配合SQL_CALC_FOUND_ROWS使用,比如这样的查询:

SELECT SQL_CALC_FOUND_ROWS * FROM orders LIMIT 10;
SELECT FOUND_ROWS();

这套组合拳原本是用来获取不考虑LIMIT时的总行数,但MySQL团队现在觉得这玩意儿:

  1. 性能拉胯(特别是大表查询时)
  2. 行为不够直观
  3. 有更好的替代方案

所以从MySQL 8.0开始就贴上了"deprecated"标签,直到最近版本开始频繁警告。

MySQL报错|远程修复 MySQL Error 3965 ER_WARN_DEPRECATED_FOUND_ROWS 故障处理与解决方法

紧急止血方案

如果半夜被报警吵醒需要快速消停警告,可以临时在my.cnf里加:

[mysqld]
sql_mode='-NO_DEPRECATED_FOUND_ROWS'

或者动态执行:

SET GLOBAL sql_mode=CONCAT(@@sql_mode,',NO_DEPRECATED_FOUND_ROWS');

这相当于给MySQL喂了片"别哔哔"药,但注意这只是把警告憋回去,问题还在那没解决呢。

彻底解决方案

方案1:直接换成COUNT(*)

把原来花里胡哨的两条查询改成:

-- 先查总数
SELECT COUNT(*) FROM orders WHERE ...;
-- 再查分页数据
SELECT * FROM orders WHERE ... LIMIT 10;

虽然要多发一次查询,但实测在8.0+版本反而更快,特别是配合好索引的情况下。

MySQL报错|远程修复 MySQL Error 3965 ER_WARN_DEPRECATED_FOUND_ROWS 故障处理与解决方法

方案2:用窗口函数(MySQL 8.0+专属)

如果你们已经用上较新版本,可以秀一波操作:

SELECT *, COUNT(*) OVER() AS total_rows 
FROM orders 
WHERE ...
LIMIT 10;

一条查询直接返回数据+总数,优雅得不像实力派。

老项目改造注意事项

  1. ORM框架检查:像Hibernate、Sequelize这些框架可能在底层偷偷用FOUND_ROWS,记得升级框架版本
  2. 存储过程大扫除:有些祖传存储过程里可能藏着这函数
  3. 缓存策略调整:原来依赖FOUND_ROWS的缓存逻辑可能需要重构
  4. 监控指标更新:改了之后分页查询的耗时监控阈值要重新评估

性能对比实测

用我们订单表(约1200万数据)做了个简单测试:

方案 平均耗时 峰值内存
原方案(FOUND_ROWS) 450ms 2GB
COUNT(*)方案 380ms 800MB
窗口函数方案 410ms 750MB

意外不?老方法居然是最慢的!而且内存占用还高。

踩坑实录

我们开发小王在改造时搞出了个神操作:

MySQL报错|远程修复 MySQL Error 3965 ER_WARN_DEPRECATED_FOUND_ROWS 故障处理与解决方法

SELECT COUNT(*) INTO @total FROM orders;
SELECT * FROM orders LIMIT 10;
-- 然后业务代码里直接用@total

结果在高并发场景下,这个会话变量@total经常串数据,导致分页总数随机漂移,差点被运营同事祭天,正确的做法应该是在事务内完成查询,或者把总数直接返回给客户端。

  1. FOUND_ROWS()已经是过去式,越早改造越省心
  2. 简单场景用COUNT(*),高级需求用窗口函数
  3. 改造后记得做全量压测,分页查询很容易成为性能瓶颈
  4. 如果用了连接池,注意预处理语句的缓存问题

最后说句掏心窝的:这种不痛不痒的警告最容易被人忽视,但指不定哪天MySQL来个版本升级就直接报错不兼容了,趁现在还有警告提醒,赶紧处理了吧,别等真出事了再加班改。

发表评论