1.E-R关系策略的由来

join是关系数据库最常用的一个特性,然而在分布式环境中,跨分片的join最复杂,最难解决。

这是官方文档的描述。


具体点,比如:

mycat逻辑库hello,两张表格t1,t2。做了分库策略,t1放到了datanode1,t2放到了datanode2。如果我t1 join t2检索数据,

怎么办?

这就是E-R关系策略要解决的问题。


mycat借鉴了table group的概念,将子表的存储位置依赖于子表,并且在物理上紧邻存放,解决了join的效率和性能问题。E-R关系的数据分片策略,根据这一思路,将子表的记录和所关联的父表记录存放在同一个数据分片上。


2.测试官方教程文档上的E-R关系表


customer采用sharding-by-intfile(分片枚举)策略,分片在dn1,dn2上,orders依赖父表进行分片,两个表的关联关系为orders.customer_id=customer.id。

	<table name="customer" primaryKey="ID" dataNode="dn1,dn2"
			   rule="sharding-by-intfile">
		<childTable name="orders" joinKey="customer_id" parentKey="id"/>

  </table>

解释:

   <table name="customer" primaryKey="ID" dataNode="dn1,dn2"
			   rule="sharding-by-intfile">

这一行是定义customer表,主键是id,分片部署在dn1,dn2,分片规则是sharding-by-intfile

 <childTable name="orders" joinKey="customer_id" parentKey="id"/>

   这一行是定义orders是childtable。

   childtable是依赖父表的结构,就是前面时候的E-R关系的表。

   childtable的joinkey会按照父表的parentkey一起切分。

</table>

   这是对应  <table name=  的结束格式,参考xml格式。


3.

表格设计:


   customer表

   id(primarykey)   name    city   (用city做分片)


   orders表

   customer_id(primary key)    orders   


   两表格关系:

   customer表的主键id为orders表主键customer_id的外键


4.mycat上实际测试:


  停止mycat服务,修改配置文件,如下:

[root@ha1 conf]# cat schema.xml 
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<schema name="hello" checkSQLschema="false" sqlMaxLimit="100">
		<!-- auto sharding by id (long) -->
		<table name="t1" dataNode="dn1,dn2" rule="sharding-by-intfile" />

		<!-- global table is auto cloned to all defined data nodes ,so can join
			with any table whose sharding node is in the same data node -->
		<table name="t2" primaryKey="ID" type="global" dataNode="dn1,dn2" />
		<table name="t3" dataNode="dn1" />
		<table name="t4" dataNode="dn2" />
		<table name="customer" primaryKey="id" dataNode="dn1,dn2"
			   rule="sharding-by-intfile">
		<childTable name="orders" joinKey="customer_id" parentKey="id"/>

 		 </table>
	</schema>
	<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
		/> -->
	<dataNode name="dn1" dataHost="mysql1" database="db1" />
	<dataNode name="dn2" dataHost="mysql3" database="db2" />

		<dataHost name="mysql1" maxCon="1000" minCon="10" balance="3"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<!-- can have multi write hosts -->
		<writeHost host="hostM1" url="192.168.211.138:3306" user="root"
				   password="Alex2010@">
		</writeHost>
		<writeHost host="hostS1" url="192.168.211.139:3306" user="root"
                                   password="Alex2010@">
                </writeHost>

	</dataHost>	

	<dataHost name="mysql3" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="192.168.211.142:3306" user="root"
                                   password="Alex2010@">
                	<!-- can have multi read hosts -->
			<readHost host="hostS2" url="192.168.211.142:3306" user="root" password="Alex2010@"/>
		</writeHost>
	</dataHost>	

</mycat:schema>


定义分片规则:

           <tableRule name="sharding-by-intfile">
                <rule>
                        <columns>city</columns>
                        <algorithm>hash-int</algorithm>
                </rule>
        </tableRule>
 <function name="hash-int"
                class="io.mycat.route.function.PartitionByFileMap">
                <property name="mapFile">partition-hash-int.txt</property>
                <property name="type">1</property>
                <property name="defaultNode">0</property>
        </function>
      [root@ha2 conf]# cat partition-hash-int.txt 
	gz=0
	sz=1


启动mycat,创建表格:

   mysql> create table customer(id int not null primary key,name varchar(10),city varchar(20));
Query OK, 0 rows affected (0.11 sec)
  mysql> create table orders (customer_id int not null primary key,orders int not null,foreign key(customer_id) references customer(id) 
on delete cascade on update cascade);
Query OK, 0 rows affected (0.25 sec)


customer插入数据测试:

   mysql> insert into customer(id,name,city) values(1,'am1','gz'),(2,'am2','gz'),(3,'am3','sz');
   mysql> select * from customer where city='gz';
+----+------+------+
| id | name | city |
+----+------+------+
|  1 | am1  | gz   |
|  2 | am2  | gz   |
+----+------+------+
2 rows in set (0.08 sec)
mysql> explain select * from customer where city='gz';
+-----------+----------------------------------------------------+
| DATA_NODE | SQL                                                |
+-----------+----------------------------------------------------+
| dn1       | SELECT * FROM customer WHERE city = 'gz' LIMIT 100 |
+-----------+----------------------------------------------------+
1 row in set (0.01 sec)

gz的数据都在dn1实现了分片。


orders插入数据测试:

    mysql> insert into orders(customer_id,orders) values(1,10001);
Query OK, 1 row affected (0.33 sec)

mysql> insert into orders(customer_id,orders) values(2,10002);
Query OK, 1 row affected (0.29 sec)

mysql> insert into orders(customer_id,orders) values(3,10003);
Query OK, 1 row affected (0.48 sec)

   

根据E-R分片规则,orders表格根据外键的值也就是customer的主键值切分,

也就是orders.customer_id=customer.id的数据分在一个区。

分别在db1,db2检索数据,看看是否达到E-R分片的设计要求。