共计 1402 个字符,预计需要花费 4 分钟才能阅读完成。
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 中,那又是从另外的角度去解决了。