Mysql索引字段长度限制
需求:
登陆管理表,将历史密码表(哈希后),历史邮箱表,登录记录表(v4 and v6),token历史表连接到user表。
表结构和约束条件都很清晰,分别创⽴以下列:
编号列明类型限制
1user_id INT primary key
2user_pwd VARCHAR
3user_pwd_logid VARCHAR unique key
4user_email VARCHAR
5user_email_logid VARCHAR unique key
6user_login VARCHAR
varchar2最大长度7user_login_logid VARCHAR unique key
8user_auth VARCHAR
9user_auth_logid VARCHAR unique key
进⼀步需求:考虑到logid的不可重复性,在⽣成此类ID时需要考虑⾃创UUID的长度,UUID规则⽬前没有设计好。
OK,出现问题了。如果UUID的规则没有设计好,意味着各种logid列的长度是当前表设计的时候不可知的。于是开始打VARCHAR长度的主意。这⾥会涉及到⼀个坑,MYSQL使⽤innoDB引擎时候的ROW SIZE限制在对于设置了unique key的列时候不是共享的,⽽是每个unique 的列⾃⼰有⼀个最⼤值的。
以下是掉进坑⾥挣扎和最终爬出来的过程:
看到这种验证逻辑,很明显就是需要事务出来⼲活了,因此选⽤了innodb引擎,根据MYSQL8.0⼿册,所有列共享了ROW SIZE限制。但是⼿册上在varchar这⼀部分没说的是这时候作为 unique key做了索引的列来说,限制是3072字节。结果我就掉到坑⾥去了,以使⽤UTF-16对接java 11 程序考虑,⼀个字符是2-4字节,数据库建表时候取了4字节作为默认值,也就是说如果限制成unique,在使⽤UTF16编码前提下只能放进去最多768个字符。因为UUID⽣成规则⽬前不明,我随⼿就⽤了个VARCHAR(1000)结
果就报错了。后期的修改过程中,⼜因为其他列长度限制的影响完全忽略了那些logid是带着unique的索引列。这下⼦可好玩了,字符数量的限制⼀会⼉是65535/4约为16000个字符,⼀会⼉是3072/4 = 768字符,脑袋彻底乱掉了。最后还是社区⾥⼀位⼤佬帮忙,⼀眼看到了报错信息中的specified key这个关键词,指出设计时候这⾥出错了,这才从坑⾥⾯爬出来了。
总结经验教训:
1 下次尽可能要求UUID长度定下来以后再设计表,不要⾃信⼼爆棚以为随便给个⼤值就能兼容后⾯⼀切捣腾,虽然想到了使⽤unique限制UUID这种连进来的外键来避免UUID算法可能产⽣的碰撞,但是unique限制后会触及数据库底层效率架构,在设计表,迁移数据等场景下都可能产⽣问题。
2 掉进坑⾥后⾃⼰扑腾的时候要回去看设计图,看⽂档要⽐盯着SQL错误信息和deadline发慌有效太多了
3 必要时候最好使⽤远程数据库或者内⽹独⽴服务器验证避免陷⼊开发环境遭到暗中破坏这种想法,有个对⽐试验的环境最好了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论