1.简介公司目前在做服务分离和数据切分的工作,因为订单和订单项表的数据量太大,而且每天都有50万的数据量在增长。基于目前的情况,项目组决定采用分库的方式来解决目前的问题。那么如何拆分呢?拆分数据库的策略其实比较简单。主要是确定拆分的领域和策略。一开始想按主键ID的奇偶数来分两个库。order_1库主要用于存储奇数id,order_2库主要用于存储偶数id。但是这种切分是非常有限的,因为最多只能分成两个库。如果数据量大了,后面再划分就不难了。然后又想到另一个分片字段:cityID,因为order表上有一个cityID属性,我们可以根据这个来分库,但是全国有几百个城市,不可能分几百个库ortables,最后讨论的结果是:城市ID生成,固定大小,默认三位数,100-999将order表分三个库,order_1,order_2,order_3当城市ID在100-399范围内,作为城市ID存入order_1库中。400~699范围内,存入order_2库中。当城市ID在700~999范围内时,会存入order_3库,按城市ID分片。如果后期订单数据量太大,可以进一步分库!基于Mysql数据库,应用最广、最成熟的分布式中间件当属Mycat。不过自从用Mycat中间件分库后,发现了很多坑。一起来看看这些坑吧!功能上线后,当测试人员继续从页面最后一页开始查询订单数据时,运维平台突然报监控到很多慢SQL告警。以下是运维平台监控到的慢SQL。SELECTidFROMorderWHEREOderCreateTimeBETWEEN'2021-05-0100:00:00'AND'2021-06-0100:00:00'ORDERBYidDESCLIMIT0,151400于是,运维同学开始找我们,说我们的程序有问题,开始抱怨关于我们开发组里写的是什么,但是我们开发坚信程序没有问题。通过查询日志,我们发现代码的查询语句长这样。SELECTidFROMorderWHEREOrderCreateTimeBETWEEN'2021-05-0100:00:00'AND'2021-06-0100:00:00'ORDERBYidDESCLIMIT151300,100与实际运维给出的慢SQL语句中的LIMIT0,151400完全不符。我们也自己review了代码,把sql日志截图了,去找技术总监讲道理。随后,当测试人员再次点击逐页查询时,运维又监控到了LIMIT0,151400的诡异SQL。我们花了几个小时排查并在本地跑了测试,仍然没有发现任何问题。我真的感觉到了。你要怀疑自己的人生!多次测试的时候,每次都能重现这个问题,让我想起了一个问题,Mycat在分页的时候是否扫描了整张表。后来查阅资料,才发现原来真的有这么个坑!在分库分表的情况下,当limit的起始位置特别大时,比如大于某个表的总行数时,mycat会查询每个分表的结果集-table并返回,然后在mycat中合并排序,返回结果。比如你原来的sql语句是这样的:SELECT*FROMtable_nameWHEREtype='xxx'ORDERBYcreate_timeLIMIT10000,1000,通过mycat执行的结果会是这样的:SELECT*FROMtable_nameWHEREtype='xxx'ORDERBYcreate_timeLIMIT0,11000如果结果集是特别大的话,会导致查询很慢,严重的话会直接导致mycatOOM!所以在分库分表的情况下,不要使用mycat进行大规模的数据分页查询,通过条件过滤减少分页数据的大小!2.2.查询结果偶尔不完整当通过某些条件过滤行项目数据时,测试人员报告某些数据偶尔不完整。具体SQL操作如下:selectid,productNamefromorderItemwhereorderIdin(selectidfromorderwhereuserName='张三')预期查询结果:1,"Chocolate"2,"Coke"3,"Jelly"4,"Applephone"但是实际查询的时候,有是结果如下:1、“巧克力”2、“可乐”4、“苹果手机”上网查询相关问题。在分库分表的情况下,子查询偶尔会查询不到完整的数据,在mycat中也会出现内部死锁,所以在代码中尽量不要使用子查询,而是使用主键ID或者单表查询的索引字段,将大大提高效率!2.3.cross-shardjoin的问题是历史代码造成的,订单服务中有大量的表连接操作,例如:selecta.*,b.accountName,c.addressfromorderaleftjoinaccountbona.accountId=b.idleftjoinaccount_addressconb.id=c.accountIdwherea.orderId=11110011但是通过mycat查询后,直接报错!原因是:mycat目前只支持两张分表的join。如果要支持多表,需要自己修改程序代码或者修改Mycat的源码。2.4.不支持部分SQL语法。在实际使用中,发现有些SQL语句是不支持的。复制insert(不支持)insertinto……select.....complexupdate(不支持)updatea,bseta.remark='remark'wherea.id=b.id;复杂删除(不支持)deletefromajoinbona。id=b.id;另外,不支持跨库连表操作!2.5.有一点不支持存储过程的创建和调用。你需要注意它。在使用mycat中间件连接数据库时,如果代码中写了存储过程等语句,mycat是不支持调用的,尽量不要使用!3、小结虽然上面说的mycat有一些坑,但是这些坑还是可以通过一些优化的方法来避免的。其实mycat作为分库分表的中间件也有很多优点,比如下面官网的介绍。据了解,mycat是目前最成熟、应用最广泛的中间件,所以大家在使用的时候,大可不必有任何顾虑。对于以上陷阱,尽量避免。
