开发者学堂课程【全面讲解开源数据库中间件MyCat使用及原理(三):MyCat-架构剖析-核心技术之跨库 join 实现】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/757/detail/13303
MyCat-架构剖析-核心技术之跨库 join 实现
内容介绍
一、跨库的连接查询
二、全局表
三、 ER 表
四、catlet
一、跨库的连接查询
MyCat 如何完成跨库的连接查询,关于跨库的连接查询给大家举一个例子。
当我们写一条 SQL 语句,写 select*from tb_order o ,给它起个别名。然后还有一张表—— tb_city ,我们叫它 C ,这两张表它们要通过外耳条件来消除笛卡尔积,就是 o.cityid=c.id。
这个 SQL 语句的作用是什么呢?它要查询什么信息呢?
o 代表的是 order 订单表, C 代表的是 city 表,城市表。在订单表当中有一个外界 cityid , ctyid 指的是城市的 id 。我们得知道订单是哪个省份哪个城市下的,此时,我们就可以通过 cityid=c.id 来销售笛卡尔积,然后后面再加上一个条件—— and o.id=某个数值。根据订单的 ID 查询订单及其对应的城市信息,现在是一个很简单的多表查询,涉及到两张表。一张表是 order 表,另外一张表是 city 表。跨库的join操作实际上指的是在进行分库分表的时候,两张表可能会分到两个数据库当中,这个时候就会存在跨库的 join 问题。如何解决这个问题呢?
二、全局表
第一种解决方案,通过全局表,这个指的是在很多的业务系统当中会存在一些基础信息表。
哪些是属于基础信息表呢?
比如,数据字典表、省份表、城市表,这就是上面提到的 city ;区域表、语言表,这些都是基础信息表。这些表当中的数据量并不大,并且这些表和业务表之间存在关系,但不是业务的主从关系,而是一种属性关系。
这时我们可以将这些表当中的数据作为全局表存在,作为全局表存在指的是在 MySQL 的各个节点当中都会有这些表,都会有这些数据。如果在 MySQL 的各个节点当中都会有这些数据,那么这个时候也就相当于不会跨库的 join 操作,本地当前这个数据库节点就可以实现查询。
全局表的特点
第一个特点:全局表的 insert、update、delete 操作会实时的插入到所有节点,在所有节点当中同步执行,保持各个节点数据的一致性。
第二个特点:全局表的查询操作会从任意节点执行,因为所有节点数据都一致。
第三个特点:全局表可以和任意表进行 join 操作。因为不管另外一张表在哪个数据库当中, city 表三个数据库当中都有。此时就不会存在跨库的 join 操作。
这就是第一种解决方案通过全局表实现。
全局表之前也用过,只不过是在 table 当中,加上一个属性 global ,就声明为全局表。这是跨库 join 的第一种解决方案,通过全局表实现。
三、ER 表
第二种解决方案,通过 ER 表。
关系型数据库当中是基于实体关系模型的, MyCat 中的 ER 表便是来源于此。当我们插入数据的时候,子表的记录与其关联的父表的记录会在同一个分片当中。大家现在对于我们订单这一块的表结构来说,可能会有这么两张表,一个叫做 order ,一个叫做 order_ item ;order 表是订单表, order _item 表是订单明细表。
在插入订单以及订单明细的时候,操作的是 MyCat , MyCat 会根据我们所配置的分线规则将某条数据插入到其中的一个节点。假如,插入到第一个节点,插入的时候怎么插入呢?既插入订单,又插入明细。如果我们将订单插入到第一个节点,明细插入到第二个节点,那么接下来我们去查询的时候,就会存在跨库的 join 操作。如何解决这个问题呢?
当我们插入订单的时候,假如我们插入了一个订单,订单的 ID 是1000,那么接下来,当我们再去插入 1000 这个订单所关联的明细的时候,这个时候怎么办呢?
我们把 1000 这个订单所关联的明细,我们也插入到同一个节点当中,那么这个时候就相当于 1000 这个订单和 1000 这个订单所关联的明细都在同一个节点当中,此时也就解决了跨库的 join 操作。因为是同一个数据,这就是第二个解决方案,基于 ER 表来完成跨库的 join 操作。
四、catlet
第三种方案,通过 catlet 实现跨库 join 。
catlet 是 MyCat 为了解决跨库的分线 join 提出的一种创新思路,它也叫HBT人工智能。
这个主要是借鉴了数据库当中的存储过程来完成的。如果我们要使用 catlet 这种方式,那么用户需要根据系统提供的 API 接口手动的实现 join ,也就是说 MyCat 当中给我们提供了一个接口,我们可以通过自定义这个接口的实现类来完成跨库的 join 操作,这个接口就是 catlet 接口。
我们直接搜一个 catlet 就这个接口。
在这个接口当中有两个方法,一个是 process SQL ,一个是 route 。
process SQL 这个方法,是用来执行 SQL 语句,并给客户端返回结果集,这个就是用来执行 SQL 语句。 Route 这个方法,是路由的方法,就是用来传递我们系统的配置等相关信息。这里可以拿到系统的配置,可以拿到 schema 当中的配置,可以拿到 catlet 的类型,也可以拿到真实的 SQL 语句,以及字符集,还有对应的连接信息。
在 route 方法当中,我们就可以实现别人的路由操作。这是 MyCat 当中给我们提供的一个接口,我们可以根据这个接口去定义它的实现类。实现类定义好之后,我们可以将这个实现类进行一个编译,并且将它存放在 MyCat 安装目录下,有一个目录就叫 catlet 。
MyCat 的安装目录下就会有一个目录,叫做 catlet 。
catlet 这个目录将我们编写好的 class 的字节码文件存放在 catlet 这个目录下。当我们隔了一分钟之后,这个文件就会被扫到并且更新,然后进行一个下载,这个过程我们不需要重启 MyCat 的图,当然你也可以选择重启。
所以,用 catlet 这种形式实现跨库的 join ,第一步:先定义这个类对应的实现类,第二步:将这个实现类进行编译,将编译后的字节码文件存放在 MyCat 安装目录下的 catlet 。
catlet 是一个接口,如果我们不想使用这种方式,那么我们可以选择使用全局表以及 ER 表。如果要使用这种方式 ,MyCat 当中有没有提供对应的实现呢?
这个里面有一个实现,叫做 Share join ,它是一种什么样的分片方式呢?或者说什么样的 join 方式?
Share join 是 catlet 的实现,也就是 catlet 这个接口的实现类。它可以做一个简单的分片 join ,目前仅支持两张表的 join 。 share join 的核心是解析 SQL 语句,在 route 里面做一系列的操作解析SQL 语句。
解析完 SQL 语句会将 SQL 语句拆分成单表进行查询,然后把在各个节点的数据进行汇总。所以 share join 实际上就是把一条复杂的 SQL 语句拆分成多个单表操作,拆分完之后,路由到各个节点,或者说分发到各个节点进行执行,然后再把各个节点执行的结果返回 MyCat 当中进行汇总。
我们如果想使用 catlet 完成 join ,除了需要定义 catlet 的实现类,或者用 MyCat 当中提供的实现类以外,我们还需要用到 MyCat 当中的注解。
在执行SQL语句的时候,我们怎么选择,用不用 catlet 以及用哪一个 catlet 的实现,此时我们需要在 SQL 语句执行之前,加上 MyCat 当中的注解,“/* */”就是注解。
指定 SQL 语句在执行的时候要使用 MyCat 当中的 share join 的 catlet 。