本文转载自微信公众号《董泽润的技术笔记》,作者董泽润。转载本文请联系董泽润技术笔记公众号。上一篇弱智MySQLNULL的帖子,居然有小伙伴留言说业务上依赖NULL导致联合索引不唯一。例如,一些用户需要多条记录,而另一些用户只有一条。看完差点吐老血。在DB中耦合业务逻辑真的合适吗?如果外包是另外一回事,谁接下了正常的项目谁就倒霉。今天讨伐json的又是一批json。去年分享过mysqljson引起的故障。今天的案例其实是去年的姊妹篇,原理完全一样。不推荐使用json的原因有两个:TableSchema强一致,约束开发不要乱。json的弱约束就是开后门。时间一长,json字段就会变成下水道。MySQLJSON很垃圾,5.7系列有性能问题,beta8.0好多了。强烈建议大家,在使用之前,对上面提到的两点进行压力测试。以上两点有争议吗?如果有争议,如果同意是垃圾,谁来讨论?现实JSON有两种表示方法:文本可读的在mysql中对应json_dom.cc,二进制表示的对json_binary.ccBinaryFormatIfthevalueisaJSONobject,itsbinaryheaderrepresentationwillhavea:-themembercount-thesizeofthebinaryvalueinbytes-alistofpointerstoeach-alistofpointerstoeachvalueTheactualkeysandvalueswillcomeaftertheheader,inthesameorderasintheheader.同样,如果值是一个JSON数组,二进制表示将有一个headerwith-theelementcount-thesizeofthebinaryvalueinbytes-alistofpointerstoeachvalue源代码中的注释也写得很清楚。二进制分为两部分:header+element。其实mysql只是一个识别json的服务器,各个存储引擎存储的还是二进制blob。换句话说,底层引擎并不知道jsonjson-function-reference[1]官方说在server层操作json的方式有很多种。如果您有兴趣,可以看看我们的问题。MySQLClient读取json时,json_dom调用wrapper_to_string方法,序列化为可读格式数据写入json时,json_binary调用serialize_json_value方法,序列化为上图所示的二进制数据,然后存储到blob中由引擎层格式化。去年的失败也是服务器端的问题:主动加载单条数据失败paniced不浅(原因是数据不一致,宁愿不对外提供服务,但是问题是数据很重要)。所以这个故事告诉我们:在线服务的可用性比数据一致性要慢得多,因为wrapper_to_string在遇到大量json数组时,会用mem_realloc反复创建内存空间,导致性能下降。事实上,去年没有修复。也有类似的问题,不过是在serialize_json_value写入存储引擎之前重复mem_realloc导致超时。这时前端页面发现写入超时,(手动)重试继续写入json数据,正好赶上了联合索引中的NULL字段,导致出现unique的现象索引不是唯一的。那么如何解决呢?前端的冷却按钮是治标不治本。sql执行12秒后,前端必须再次点击提交。根本原因要升级到mysql8.0,去掉NULL字段。会不会引入其他问题?我在项目之初就做出了一个错误的决定,很容易让后人买单。希望我们踩过的坑让你犹豫几秒再决定用json^^8.0fix在测试机上,发现8.0还可以,没有性能问题,查看提交的commit,有人发现itin2016andfixedit,no知道有没有backport到mysql5.7那几个版本commita2f9ea422e4bdfd65da6dd0c497dc233629ec52eAuthor:KnutAndersHatlen
