一台 MySQL 5.6 跑了四年,数据 1.8 G,想升到 8.0。备份完之后导进去,站点直接 500。

错误日志里全是这个:

SQLSTATE[HY000]: General error: 1055 Expression #1 of SELECT list
is not in GROUP BY clause and contains nonaggregated column

四个坑,挨个说。

一、ONLY_FULL_GROUP_BY

MySQL 5.6 的默认 sql_mode 是空的。GROUP BY 可以随便查不在分组里的列,取哪一行由它自己决定。

8.0 默认开了 ONLY_FULL_GROUP_BY,这种写法直接报错。

先看当前模式:

SELECT @@sql_mode;

8.0 出来是一长串:

ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,
NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

两个选择:改 SQL,或者关掉这个模式。

长期看肯定要改 SQL。但 WordPress 生态里一堆老插件写死了这种查询,短期只能先关:

[mysqld]
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

写进 /etc/my.cnf,重启生效。注意别整段清空,STRICT_TRANS_TABLES 还是有用的,能挡住字段超长这类脏数据。

二、NO_ZERO_DATE

这是白屏的另一个来源。WordPress 有些老表(尤其是插件建的)字段默认值是 0000-00-00 00:00:00,8.0 严格模式下插入直接报错。

先查有没有这种行:

SELECT COUNT(*) FROM wp_posts
WHERE post_date = '0000-00-00 00:00:00';

有的话先修数据再升级:

UPDATE wp_posts SET post_date = '1970-01-01 00:00:00'
WHERE post_date = '0000-00-00 00:00:00';

不改的话,导数据那一步就会卡住。

三、认证插件 caching_sha2_password

8.0 把默认认证插件从 mysql_native_password 换成了 caching_sha2_password。老版本 PHP 的 mysqli 不认,报:

mysqli_real_connect(): The server requested authentication
method unknown to the client [caching_sha2_password]

三个办法,推荐第三个:

  1. 全局降级认证插件(不推荐,安全性下降)
  2. 升级 PHP 到 7.4 以上
  3. 只给 WordPress 这个用户单独设回 native
ALTER USER 'wpuser'@'localhost'
IDENTIFIED WITH mysql_native_password BY '你的密码';
FLUSH PRIVILEGES;

这样其他账号还是新插件,只有 WordPress 用老的。兼容性和安全性取个中间值。

四、排序规则变了

5.6 用 utf8mb4_general_ci,8.0 默认 utf8mb4_0900_ai_ci。两个影响:

第一,JOIN 两个不同排序规则的字段会报错:

Illegal mix of collations (utf8mb4_general_ci,IMPLICIT)
and (utf8mb4_0900_ai_ci,COERCIBLE) for operation '='

第二,大小写和重音的判断变严了。原来某些比较里 Abc 和 abc 算相等,现在不一定。

最稳的做法是新建库时显式指定成老排序规则,让整库保持一致:

CREATE DATABASE wp DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;

导出导入两边都带字符集参数,能避免 90% 的乱码:

mysqldump --default-character-set=utf8mb4 -u root -p wp > wp.sql
mysql --default-character-set=utf8mb4 -u root -p wp < wp.sql

五、GROUP BY 不再隐式排序

这个最阴。不报错,只是结果顺序变了。

5.6 里 GROUP BY 会顺带按分组字段排序,8.0 取消了。所以原来"按时间倒序"的列表,升级后变成乱序,分页跟着乱。

解决很简单,SQL 里显式写 ORDER BY:

SELECT post_id, COUNT(*) AS c FROM wp_down
GROUP BY post_id ORDER BY MAX(create_time) DESC

如果代码不是你的,就只能加补丁,或者忍受乱序。

升级步骤

顺序很重要,别直接动生产库:

  1. 全量备份,mysqldump 和物理文件各一份
  2. 测试机装 8.0,导入数据
  3. 跑一遍站点,重点看后台列表页、分页、搜索
  4. 记录所有报错,改 SQL 或者调 sql_mode
  5. 生产环境停站 30 分钟,重复步骤 2 到 3
  6. 开一小时 general_log,盯着有没有静默失败
项目 5.6 表现 8.0 表现 影响
GROUP BY 非聚合列 随便取一行 报 1055 错误 页面 500
零日期字段 能插入 报错 写入失败
认证插件 native caching_sha2 连不上库
排序规则 general_ci 0900_ai_ci JOIN 报错、乱码
GROUP BY 排序 隐式升序 无序 分页错乱

升级数据库最大的风险不是"升不上去",而是"升上去了,但某条查询悄悄变了结果"。报错的都好办,不报错的才要命。

俗人源码网免责声明:

1、本站所有资源均收集于互联网,分享目的仅限学习与参考。如有侵权,请联系 1685698671@qq.com 及时删除!

2、本站资源不保证完整性和安全性,下载后请自行检测。使用过程中出现的任何问题均与本站无关,敬请自行处理。

3、本站资源仅限个人学习研究使用,严禁用于任何违法违纪用途。因使用者违规使用产生的一切后果,由使用者自行承担,本站不承担任何责任。