之前在发了一篇文章,标题为“Halo数据正式兼容MySQL5.7”,介绍我司Halo数据库兼容MySQL5.7的第一个正式版本,这个版本在我们内部称之为Halo-MySQL V1.0。Halo-MySQL V1.0推出半年多来,已经在几个客户公司落地运行,成功的将客户公司的MySQL数据库应用场景切换到我们Halo-MySQL数据库应用场景,反馈情况很好。
V1.0正式发布之后,我们积极参与市场推广,花了一些时间支持我们产品在各个客户应用场景的落地工作,同时收集客户的反馈。
然后今年3月份,我们确定了V2.0的开发计划。如果说V1.0和MySQL5.7的兼容度达到95%的话,那么我们V2.0的目标是把兼容度提高到98%,以便能更好的支持和满足各种客户的需求,让客户从官方MySQL切换到我们Halo-MySQL的过程更加顺滑。历时3个多月之后,V2.0终于出炉。
今天的文章,我就来讲讲我们Halo-MySQL V2.0实现的主要功能。
主要分三个方面来讲:语法,系统函数,操作符。
1、语法
在V1.0版的计划阶段,我们就收集了不少MySQL和我们Halo数据库的语法差异,并且根据我们对这些语法的实用性,以及我们开发的迭代周期,做了优先级排序,将一些不是太常用且实现难度较高的语法放到后续版本中。
1)last_insert_id
MySQL中,last_insert_id是在insert into的返回结果中,携带刚刚执行成功的insert into语句对应的自增列的id值,主要是针对自增列,返回的这个值可以用在一些业务场景中。这个语法不算太常用,不过也确有一定的实用性。
Halo本身并不支持这个特性。不过有一个类似的功能,但用法上有很大的差异。我们就从这个类似的功能入手,最终实现了MySQL的last_insert_id特性。
2)only_full_group_by
MySQL中有个特性,可能会让其他数据库的用户哭笑不得,那就是“only_full_group_by”特性(我暂且这么命名他)。“only_full_group_by”是MySQL的一个参数,大家查一下就能很快明白其意思,也就是说通过这个参数,可以控制是否允许查询目标列不出现在Group by中(或者聚合函数中)。咋一看,这是很不严谨的做法,有些违背SQL标准,但是MySQL就是支持,而且还真有一些很传统的客户业务场景中这么用了。那么除了支持,我们没有第二个选择。
3)join…join…join…on / where
一般我们写SQL,如果要连接3个或更多的表做查询,使用join时,更喜欢一个join后跟一个on,例如join…on…join…on…join…on,这样能更直观地看清楚各个join的条件,SQL的可读性和可维护性更好。但是MySQL还支持把所有的join写在前面,后面只跟一个on,所有的join条件都放在这个on后面。这个问题是在一个近万个字符长的超级SQL中暴露出来的。一看到这个问题,我直奔语法文件,先是分析研究了相关的语法规则,然后做了各种尝试,结果都是一大堆的冲突错误,顾此失彼,感觉非得把语法文件改得面目全非才能支持好这个“另类”,但是这样的话风险和后续的可维护性又是一个大问题。最后另辟蹊径,才搞定这个问题。另外,MySQL还支持把这个on替换为where,我们也支持。
4)多表Update
相信近十来年,在互联网环境下的业务开发们,很少使用多表Update(还有多表delete)特性。但是我们的客户多数都是大金融圈的公司,很多业务系统颇有历史可考,或者说开发模式相对比较传统。多表update是我们去年V1.0开始时就知道的语法,当时没有纳入V1.0版本内。现在结合我们这几个月和客户的打交道,对客户业务系统的了解,我们将其正式纳入V2.0版的开发任务中,并实现出来。
5)where条件中大小写和空格规则
这个严格的说是和字符集和字符序有关系,但是Halo的处理思路和流程对此支持有不小的差异,实际结果也是在相同的字符集和字符序行为不一致。而且”=” ,“!=”, “like”,char,varchar, text各有各的特点,交叉组合起来,要处理的场景还不少。
2、系统函数
系统函数(或者称为MySQL内置函数)方面,我们在V1.0版本中没有明确的纳入目标。在V1.0版的落地过程中,我们陆续收到一些客户对MySQL系统函数的需求,然后我们就以快速实现,提交小版本的方式快速满足客户的需求。等到对MySQL系统函数有了一定的认识积累后,我们决定在V2.0版本中正式的规范的实现一些常用的MySQL系统函数。
MySQL的系统函数还有一个特点,就是参数类型非常灵活,实现过程中需要耐心对待。
1)聚合函数
group_concat。group_concat是一个比较受欢迎的聚合函数,我们在V2.0版中将其优先考虑并实现了。
2)字符串函数
length, substring, locate, instr, left,right,concat, lcase, ucase, insert, rand, truncate, find_in_set, lpad, rpad。
以上应该是最常用的字符串函数,我们一一实现和测试。当然还有一些字符串函数用法和行为在MySQL和Halo中是一样的。
3)时间函数
sleep, sysdate, curdate, curtime, unix_timestamp, from_unixtime, makedate,maketime, convert_tz, timestampadd, timestampdiff, utc_date,utc_time, utc_timestamp, date_format, time_format, time_format, str_to_date, mid, now, sysdate, curdate, curdate_add, curdate_sub, adddate, subdate, date_add, date_sub,datediff, addtime, subtime, timediff,year, month, monthname, day,dayname, dayofmonth, dayofweek, dayofyear, last_day,week, weekofyear,yearweek, weekday, hour, minute,second, microsecond, quarter, time_to_sec, sec_to_time,period_add, period_diff, to_days, from_days。
这差不多包含了所有的时间类型相关的函数,我们也是一一实现和测试。
4)数字函数
round。
5)其他函数
field, if, isnull,ifnull, any_value。
3、操作符
操作符更能体现出MySQL的灵活性(或者换个角度说给人不严谨的感觉)。例如字符串(MySQL的字符串到数字类型的转换规则和C语言是一致的)类型值可以做加减乘除,比较,等运算。其他一些数据库也有类似的用法,但是几乎都不如MySQL这么灵活得彻底。
既然了解到有客户需要这些,那么我们就必须行动起来。几十个自定义函数,几千个测试用例。虽谈不上有多少的难度,但是也挺考验耐心。
从语法,函数,还有操作符这些来看,MySQL实在是太灵活了,灵活的完全没有章法,都不知道是该夸他,还是该骂他。但是,最终肯定是要以市场为导向,只要是客户需要的,就是我们要去做的。
以上的语法也好,系统函数或操作符也好,粗糙的实现出来貌似也能满足用户的一般需求,但是背后的很多细节并不能不管。比方说对空值,NULL值,语义上的非法值的处理,都要考虑周到。为此,我们详细的考虑和实现了这些细节,并对每个实现的语法,系统函数或操作符,都添加了大量的回归测试用例,并设计了测试场景,进行7 * 24小时的不间断测试。
在文章的最后,我对这半年多来,非常支持我们Halo-MySQL V1.0落地的客户们表示感谢,真是你们的支持和鼓励,我们才能更有信心的开始和完成V2.0版的开发。希望后续大家能更好的合作,花更少的投入,取得更大的收获。




