CHAR检索时自动去除尾部空格,VARCHAR原则上保留尾部空格,但实际行为受行格式影响:COMPACT/DYNAMIC/COMPRESSED下写入时即移除,仅REDUNDANT全程保留。

CHAR 会自动截断尾部空格,VARCHAR 则原样保留——这不是 bug,而是设计契约,且受行格式影响。
CHAR 检索时自动 trim 尾部空格
MySQL 对 CHAR 的语义定义是「固定长度、右填充空格、检索时移除尾部空格」。这个行为发生在 server 层,与存储引擎无关,也与是否启用严格模式无关。
常见错误现象:SELECT CONCAT(c, '+') 中 c 是 CHAR(5),存入 'ab '(含两个空格),查出来却是 'ab+',而不是 'ab +'。
- 即使你显式插入带空格的字符串,
INSERT INTO t VALUES ('x '),CHAR字段仍会先右填充到长度,再在读取时统一 trim - 这个 trim 不可关闭,也无法通过
SQL_MODE控制 - 唯一能绕过的方式是用
BINARY CHAR或VARBINARY,但这就脱离了字符语义
VARCHAR 保留尾部空格(但 COMPACT 行格式下写入时可能被移除)
VARCHAR 原则上保留所有空格,包括尾部——这是 SQL 标准要求。但要注意:实际是否“真保留”,取决于行格式。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
关键细节:VARCHAR 在 COMPACT、DYNAMIC、COMPRESSED 行格式中,写入时就会移除尾部空格;只有在 REDUNDANT 格式中才全程保留。
- 也就是说,如果你用默认的
innodb_default_row_format=dynamic(MySQL 5.7+ 默认),INSERT INTO t VALUES ('ab ')存进去的其实是'ab' - 验证方式:
SELECT LENGTH(v), HEX(v) FROM t,看长度和十六进制值是否匹配预期 - 想强制保留尾部空格?要么改行格式(不推荐),要么改用
VARBINARY,或在应用层加标记字符(如\0)
比较行为也跟着空格处理走
CHAR 和 VARCHAR 在 =、IN、ORDER BY 等场景下的比较逻辑,直接继承其空格处理规则。
典型陷阱:WHERE char_col = 'abc' 和 WHERE varchar_col = 'abc' 看似一样,但如果 varchar_col 实际存的是 'abc '(且行格式为 REDUNDANT),那它就不会被匹配到。
-
CHAR比较前自动 trim,所以'abc '和'abc'视为相等 -
VARCHAR比较时不 trim(除非你显式用RTRIM()),所以'abc '≠'abc' - 更隐蔽的是
GROUP BY:两个看似相同的VARCHAR值,因空格数量不同,会被分到不同组
最易被忽略的一点:空格行为不是由字段类型单独决定的,而是 CHAR/VARCHAR + 行格式 + 字符集 三者共同作用的结果。尤其当表跨版本迁移或从 MyISAM 转 InnoDB 时,REDUNDANT → DYNAMIC 的切换会让原本保留的空格突然消失,而日志里根本不会报错。

















