Mycat作为数据库的中间件,被许多我的项目用来做关系型数据库的分库分表;我目前所在的我的项目因为业务和数据量的增长,也应用Mycat来进行分库分表。最近因为一个需要须要遍历一个分库表的数据,对数据进行相应的业务操作。
例如咱们有一个user表,该表被分为16个库,那么能够如何高效而优雅的实现对user表中所有数据的遍历呢?
应用表的主键ID分页遍历
这种办法是最直接了当,也是最容易想到的;例如应用如下的sql语句分批查问表中的数据:
select * from user order by id
limit a, 10000;
该sql语句以每批1万条纪录的形式遍历user表,每次查问应用上次id的最大值替换a的值,直到没有纪录返回。
这种实现诚然可行,但其最大的问题在于效率,每次查问都会从所有的分库中各获取1万条纪录,那么Mycat总共失去16万行的数据,java培训再进行排序,取前1万条记录返回。如此遍历下来,总共查问了user表总记录数16倍的数据量,而且还进行排序,这种耗费无疑是微小的。如果分库数量更多,资源的耗费和节约更重大。此计划在性能上是不可承受的。
独自遍历每个分库
Mycat提供了通过注解的形式指定从某个分库执行sql语句,注解语法为
/!mycat:dataNode = ${dn} /
其中,dn为分片节点的名称;这样,咱们就能够对上述的查问语句进行革新,指定分片节点进行查问遍历,如:
/!mycat:dataNode = dn1 /
select * from user order by id
limit a, 10000;
应用以上的sql语句,先对名称为dn1分片节点的数据进行遍历,而后批改注解中的节点名称,持续遍历其余节点;把所有的节点都遍历实现后,user表的数据也就遍历结束。这种遍历形式大大提高了效率,不论user表被分成多少个分片,所有的数据都只被读取一次。
此办法的不足之处是必须当时获取所有分片节点的名称,写在代码或配置文件中;当分片进行扩容时,分片节点数量减少,配置文件或代码就必须做对应的批改,否则就获取不到表中所有的数据。
主动获取所有分片节点名称
那么,有没有一种办法能够实时主动的取得分库表的所有分片节点名称呢?
Mycat除了数据操作端口(默认8066)外,还提供了治理端口(默认9066),通过连贯该端口,能够查看Mycat的运行数据并做治理操作。通过治理端口登录Mycat后,能够通过show @@datanode命令查看分片节点信息,如下所示(后果已略去局部列):
NAME列即为节点名称,只有获取到该列所有的值即可。然而治理端口有较高的操作权限,个别状况下出于平安起因,该端口仅运维有权限登录操作,利用无权拜访。
还有其余更好方法吗?
这时想到了执行打算, 对,执行打算! Mycat反对explain命令查看sql语句的执行打算,对于分库表,会返回sql语句执行须要查问哪些节点;这样咱们就能够通过结构一个须要查问所有节点的sql语句来获取全副节点信息,例如通过如下所示的语句:
DATA_NODE列即为节点名称;节点取到之后,剩下的就简略了,无非是对各个节点独自遍历。这种形式通过查问一次Mycat就取得了所有分片节点的名称,java培训而且数据库的连贯也能够复用,真正做到了既高效又优雅。
当然,以上的解决方案是限定于Mycat与MySQL的范畴之内,如果数据能够同步到NoSQL中,那又是从另外的角度去解决了。