在分布式系统中,通常会遇到这样的问题,需要在一个数据库的表,关联另一个数据库的表,出现这样的场景如:
有一个记录用户注册信息的库(库1),包括用户ID,用户名,用户创建时间,等其他信息。另外有一个库(库2),记录了用户的ID信息,这个ID在所有的库中是唯一的,现在有这样一个需求,在库2根据某个条件查询,并且按照用户的登录时间排序,但是在库2根本就没有用户的注册时间,这样按照用户注册时间排序,直接操作明显不太可能。
对于上述的问题,解决方法通常有:
方案一、字段冗余。也就是说把一部分信息重复存放,比如 pay_log表里除了userid字段还有user_name字段,等等。但是这只适合加少量字段,如果把注册、登录时间、等级等等都字段都重复一遍,那是显然不科学的。
方案二、表复制和同步。也就是说把main_db里面的user_info表复制一份到log_db中,然后设置定时任务让这两个表进行同步。这样确实是可以在一个库里,然后可以进行 JOIN 等的复杂语句操作了。但是这两个表的内容是重复的,未免会比较浪费空间。
方案三、链接表。什么是链接表呢?简单来说,就是在log_db里有一个user_info表,但这个表并没有存储数据,而是直接链接到了 main_db里的user_info表。这样的话,我们可以既无需定期同步,又可以像在同一个库里使用JOIN等操作。
我们说一下第三种情况的做法:
第一步:开启 FEDERATED 引擎
以MySQL为例,链接表与常见的 MyISAM, InnoDB 等等,都是一种表的结构类型(称之为 存储引擎)。使用 show engines; 命令即可看到数据库所支持的存储引擎,默认 FEDERATED 引擎 是关闭的,我们需要去mysql配置文件开启它。
开启的方法很简单,在windows下只需要在mysql的配置文件 my.ini 最末尾加上一句 federated ,然后重启mysql即可。重启后输入 show engines;命令即可看到 FEDERATED 的 Support 变为 YES,表示federated引擎已经开启。
第二步:新建链接表(federated引擎的表)
既然是链接的表,那么会有以下几个限制:
1.本地的表结构必须与远程的完全一样
2.远程数据库目前仅限MySQL
3.不支持事务
4.不支持表结构修改
建表的语句 语法 如下
CREATE TABLE xxx(...) ENGINE=FEDERATED CONNECTION='mysql://[name]:[pass]@[location]:[port]/[db-name]/[table-name]'
当然不建议这样自己手工从头拼装SQL语句,可以把mian_db的user_info表的结构导出来,然后修改最后的半句,再导进去就行啦。建表语句示例如下:
CREATE
TABLE user_info
(
userid
int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
username
varchar(60) NOT NULL DEFAULT '' COMMENT '帐号',
level
int(11) NOT NULL DEFAULT '1' COMMENT '等级',
log_dt
timestamp NOT NULL DEFAULT '2016-11-30 00:00:00' COMMENT
'最后登录时间',
reg_dt
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间',
PRIMARY KEY (userid
),
KEY idx_name
(username
)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
CONNECTION='mysql://batsing:b8a7t4@localhost:3306/main_db/user_info'
COMMENT='用户基本信息表-链接表';
<!-截取后半句如下,指定引擎,数据库信息,表信息->
ENGINE=FEDERATED DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
CONNECTION='mysql://batsing:b8a7t4@localhost:3306/main_db/user_info'
COMMENT='用户基本信息表-链接表';
第三步:写关联语句
和正常的表关联一样写好sql语句即可!