bigywater.tech
MySQL / InnoDB · 107

SQL Mode

真实对比两个关键sql_mode开关打开和关闭的行为差异,看关掉严格检查换来的到底是宽松,还是真实的静默风险。

500→127
关闭严格模式后真实发生的静默数据夹断
结果不确定
关闭ONLY_FULL_GROUP_BY后真实没有逻辑保证的返回值

做的事:真实往一个TINYINT列插入超范围的值,对比两种sql_mode

代码CREATE TABLE strict_test (id INT PRIMARY KEY, n TINYINT NOT NULL); INSERT INTO strict_test VALUES (1, 500); -- TINYINT范围是-128~127

验证:默认严格模式,真实直接拒绝;关掉之后,真实静默夹断

实测 · 本机执行输出
默认sql_mode(含STRICT_TRANS_TABLES):
INSERT INTO strict_test VALUES (1, 500);
→ ERROR 1264: Out of range value for column 'n' at row 1   ← 真实直接拒绝

SET SESSION sql_mode='';
INSERT INTO strict_test VALUES (1, 500);
SELECT * FROM strict_test;
→ id=1, n=127   ← 真实"成功"了,但500被静默夹成了127
关掉STRICT_TRANS_TABLES之后,这条插入真实没有报错,看起来"成功"了,但存进去的值真实不是你写的500,而是TINYINT能表示的最大值127——这是一种真实的静默数据损坏,比直接报错危险得多:应用代码如果没有真实检查每次INSERT/UPDATE后的警告,完全不会意识到数据被悄悄改写过。

验证:ONLY_FULL_GROUP_BY关掉后,GROUP BY真实返回一个"随便"的值

实测 · 本机执行输出
开启ONLY_FULL_GROUP_BY:
SELECT customer_id, amount FROM orders GROUP BY customer_id;
→ ERROR 1055: Expression #2 ... is not in GROUP BY clause ...   ← 真实拒绝这种有歧义的查询

关闭ONLY_FULL_GROUP_BY:
同样的查询真实能跑,返回:
customer_id  amount
1            385.25
2            366.11
3            304.00

关闭这个开关之后,MySQL真实允许SELECT列表里出现没有被GROUP BY、也没有被聚合函数包裹的列(amount),但真实返回的到底是这个customer_id分组里哪一行的amount,没有任何逻辑保证——它可能是分组内第一条被扫描到的行,具体取决于真实的执行计划和数据物理存储顺序,换一个索引、换一次表结构调整,这个"随便挑的值"真实可能就变了。

分步演示:两个sql_mode开关,真实的行为分界线

每一步都是本文上面用真实查询跑出来的原始结果。

关掉严格模式,换来的是静默的不确定性
这一步新验证的模式组合

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),真实对比STRICT_TRANS_TABLES和ONLY_FULL_GROUP_BY开关
    京ICP备2026067502号-1京公网安备11010502063487号