比如一个大型集团公司,有一张表record保存了交易记录信息。该表数据量很大,但是查询、更新时基本都是按子公司来操作。
那么可以按子公司编号进行分表。例如子公司编号1的交易记录存储到record_1表,同理子公司编号为2的交易记录保存到record_2中…
在mysql中新建数据库实例dbcompany,并新建record0-record3,共4张表,代码如下
CREATE TABLE `record_0` ( `id` int(11) NOT NULL, `companyid` int(11) DEFAULT NULL COMMENT '子公司编号', `info` varchar(255) DEFAULT NULL COMMENT '业务信息', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `record_1` ( `id` int(11) NOT NULL, `companyid` int(11) DEFAULT NULL COMMENT '子公司编号', `info` varchar(255) DEFAULT NULL COMMENT '业务信息', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `record_2` ( `id` int(11) NOT NULL, `companyid` int(11) DEFAULT NULL COMMENT '子公司编号', `info` varchar(255) DEFAULT NULL COMMENT '业务信息', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `record_3` ( `id` int(11) NOT NULL, `companyid` int(11) DEFAULT NULL COMMENT '子公司编号', `info` varchar(255) DEFAULT NULL COMMENT '业务信息', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
通过修改conf/schema.xml,来配置真实服务器的信息,并为数据库划分节点,指定数据表所在的节点。
注意关键信息为subTables="record_$0-3"
和rule="rule-record"
,通过规则分片后,数据会落入record_0至record_3中。
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <!-- name为逻辑数据库名 --> <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"> <!-- 配置对应表名、子表名、对应数据库、规则名 --> <table name="record" subTables="record_$0-3" dataNode="dn1" rule="rule-record" /> </schema> <!-- 真实数据库名 --> <dataNode name="dn1" dataHost="localhost1" database="dbcompany" /> <!-- 配置物理数据库连接信息 --> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="127.0.0.1:3306" user="root" password="Easy@0122"/> </dataHost> </mycat:schema>
在schema.xml中我们已经制定了record表存储的节点,且设置了路由规则的名称rule-record,然后我们设置该规则具体的策略。
修改conf/role.xml,配置规则如下,注意我们是按companyid列
来进行规则应用的。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:rule SYSTEM "rule.dtd"> <mycat:rule xmlns:mycat="http://io.mycat/"> <!-- 规则 --> <tableRule name="rule-record"> <rule> <!-- 规则应用的列 --> <columns>companyid</columns> <algorithm>mod-long</algorithm> </rule> </tableRule> <function name="mod-long" class="io.mycat.route.function.PartitionByMod"> <!-- 此处设置有多少个子表即可 --> <property name="count">4</property> </function> </mycat:rule>
通过上面两个配置文件,我们已指定了库、表、分表路由规则,下面我们将其通过MyCat暴露出来,让客户端进行访问。
通过修改conf/server.xml配置MyCat对外服务信息,主要就是用户名、密码、以及上面指定的抽象数据库名称TESTDB。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:server SYSTEM "server.dtd"> <mycat:server xmlns:mycat="http://io.mycat/"> <!-- system部分采用默认即可 --> <system> <property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户--> <property name="useHandshakeV10">1</property> <property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 --> <property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 --> <property name="sequnceHandlerType">2</property> <property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false --> <!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool --> <property name="processorBufferPoolType">0</property> <!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志--> <property name="handleDistributedTransactions">0</property> <!--off heap for merge/order/group/limit 1开启 0关闭--> <property name="useOffHeapForMerge">1</property> <!--单位为m--> <property name="memoryPageSize">64k</property> <!--单位为k--> <property name="spillsFileBufferSize">1k</property> <property name="useStreamOutput">0</property> <!--单位为m--> <property name="systemReserveMemorySize">384m</property> <!--是否采用zookeeper协调切换 --> <property name="useZKSwitch">false</property> </system> <!-- 设置访问的用户名密码 --> <user name="root" defaultAccount="true"> <property name="password">123456</property> <!-- 注意此处是之前设定的抽象数据库名称 --> <property name="schemas">TESTDB</property> </user> </mycat:server>
双击bin/startup_nowrap.bat启动MyCat,然后使用Navicat或其他工具连接MyCat虚拟的数据库即可。
我们执行如下8条sql语句
insert into record (id,companyid,info)values(1,1,'test'); insert into record (id,companyid,info)values(4,2,'test'); insert into record (id,companyid,info)values(2,3,'test'); insert into record (id,companyid,info)values(3,4,'test'); insert into record (id,companyid,info)values(5,5,'test'); insert into record (id,companyid,info)values(7,6,'test'); insert into record (id,companyid,info)values(6,7,'test'); insert into record (id,companyid,info)values(8,8,'test');
执行完之后,我们看下真实物理数据库中的数据:
record_0数据如下,说明是按companyid取模匹配的,我们的策略生效了!
其他三个库也是按此规则运作的,即数据落入record_[companyid%4]
表。