MySQL8.0升级后问号字符排序早于数字异常问题咨询
问题原因
- 核心原因是你当前使用的
utf8mb4_0900_ai_ci排序规则基于Unicode 9.0标准,该标准中问号的排序权重低于数字,所以会出现"?" < "0"返回真的结果,和你预期的ASCII排序逻辑不符。 - 旧版本MySQL你大概率使用的是
utf8mb4_general_ci或旧版本的排序规则,这类规则更接近ASCII码排序逻辑,ASCII编码中问号的码值是63,数字0的码值是48,因此问号排序晚于数字,符合你之前的业务预期。 - 你测试的
SELECT "?" < 0返回0和排序规则无关,是MySQL隐式类型转换导致的:字符串和数字比较时会先把字符串转换为数字,问号无法转换为有效数字会被默认转成0,最终比较的是0 < 0,所以返回假。
修复方案
- 最优方案:修改字段排序规则(无需改业务代码)
直接修改date_field字段的排序规则为二进制排序utf8mb4_bin,完全按字符的ASCII码值排序,完全符合你的业务逻辑,执行语句:
ALTER TABLE 你的表名 MODIFY COLUMN date_field VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin [补充你原字段的其他属性,比如NOT NULL、DEFAULT等];
注意不要只修改表的默认排序规则,必须显式修改字段本身的排序规则才会生效,修改后原有查询无需改动即可正常返回结果,且不影响索引使用。
- 临时兼容方案:查询时指定排序规则
如果不方便改表结构,可以在查询时临时指定排序规则,性能远高于你当前用REPLACE的写法,示例:
SELECT * FROM table WHERE date_field COLLATE utf8mb4_bin <= CURDATE();
- 长期优化方案:调整表结构
如果业务允许调整,建议拆分字段:新增tinyint类型的is_date_unknown标记是否为未知未来日期,原日期字段改为DATE类型,未知日期统一存9999-12-31这类极大值。该方案彻底规避字符串排序问题,所有日期查询都可以走索引,性能和可读性都最好。
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

