上面介绍了可能引入分布式事务的问题,现在我们再看看需要跨节点Join 的问题。数据切分之后,可能会造成有些老的Join 语句无法继续使用,因为Join 使用的数据源可能被切分到多个MySQL Server 中了。
怎么办?这个问题从MySQL 数据库角度来看,如果非得在数据库端来直接解决的话, 恐怕只能通过MySQL 一种特殊的存储引擎Federated 来解决了。Federated 存储引擎是 MySQL 解决类似于Oracle 的DB Link 之类问题的解决方案。和OracleDB Link 的主要区别在于Federated 会保存一份远端表结构的定义信息在本地。咋一看,Federated 确实是解决跨节点Join 非常好的解决方案。但是我们还应该清楚一点,那就似乎如果远端的表结构发生了变更,本地的表定义信息是不会跟着发生相应变化的。如果在更新远端表结构的时候并没有更新本地的Federated 表定义信息,就很可能造成Query 运行出错,无法得到正确的结果。
对待这类问题,我还是推荐通过应用程序来进行处理,先在驱动表所在的MySQL Server 中取出相应的驱动结果集,然后根据驱动结果集再到被驱动表所在的MySQL Server 中取出 相应的数据。可能很多读者朋友会认为这样做对性能会产生一定的影响,是的,确实是会对性能有一定的负面影响,但是除了此法,基本上没有太多其他更好的解决办法了。而且,由于数据库通过较好的扩展之后,每台MySQL Server 的负载就可以得到较好的控制,单纯针对单条Query 来说,其响应时间可能比不切分之前要提高一些,所以性能方面所带来的负面影响也并不是太大。更何况,类似于这种需要跨节点Join 的需求也并不是太多,相对于总体性能而言,可能也只是很小一部分而已。所以为了整体性能的考虑,偶尔牺牲那么一点 点,其实是值得的,毕竟系统优化本身就是存在很多取舍和平衡的过程。
一旦进行了数据的水平切分之后,可能就并不仅仅只有跨节点Join 无法正常运行,有些排序分页的Query 语句的数据源可能也会被切分到多个节点,这样造成的直接后果就是这些排序分页Query 无法继续正常运行。其实这和跨节点Join 是一个道理,数据源存在于多个节点上,要通过一个Query 来解决,就和跨节点Join 是一样的操作。同样Federated 也可以部分解决,当然存在的风险也一样。
还是同样的问题,怎么办?我同样仍然继续建议通过应用程序来解决。
如何解决?解决的思路大体上和跨节点Join 的解决类似,但是有一点和跨节点Join 不太一样,Join 很多时候都有一个驱动与被驱动的关系,所以Join 本身涉及到的多个表之间的数据读取一般都会存在一个顺序关系。但是排序分页就不太一样了,排序分页的数据源基本上可以说是一个表(或者一个结果集),本身并不存在一个顺序关系,所以在从多个数据源取数据的过程是完全可以并行的。这样,排序分页数据的取数效率我们可以做的比跨库Join 更高,所以带来的性能损失相对的要更小,在有些情况下可能比在原来未进行数据切分的数据库中效率更高了。当然,不论是跨节点Join 还是跨节点排序分页,都会使我们的应用服务器消耗更多的资源,尤其是内存资源,因为我们在读取访问以及合并结果集的这个过程需要比原来处理更多的数据。
分析到这里,可能很多朋友会发现,上面所有的这些问题,我给出的建议基本上都是通过应用程序来解决。大家可能心里开始犯嘀咕了,是不是因为我是DBA,所以就很多事情都扔给应用架构师和开发人员了?
其实完全不是这样,首先应用程序由于其特殊性,可以非常容易做到很好的扩展性,但是数据库就不一样,必须借助很多其他的方式才能做到扩展,而且在这个扩展过程中,很难避免带来有些原来在集中式数据库中可以解决但被切分开成一个数据库集群之后就成为一个难题的情况。要想让系统整体得到最大限度的扩展,我们只能让应用程序做更多的事情, 来解决数据库集群无法较好解决的问题。