需求
一張業務表有10億數據,需要按身份證號字段certno
拆分爲4臺服務器中的16個子表,怎麼操作?
設計
使用mycat的分片功能實現分庫分表
4臺服務器,每臺服務器起一個mysql實例,每個實例創建4個database,每個database建一張同名(tu_trade_ng)的表
制定mycat的分片規則,按certno
字段的hash值進行分片
mysql 實例 | database | tablename |
---|---|---|
127.0.0.1:7006 | nifa_db_t0 | tu_trade_ng |
nifa_db_t1 | tu_trade_ng | |
nifa_db_t2 | tu_trade_ng | |
nifa_db_t3 | tu_trade_ng | |
127.0.0.1:7007 | nifa_db_t0 | tu_trade_ng |
nifa_db_t1 | tu_trade_ng | |
nifa_db_t2 | tu_trade_ng | |
nifa_db_t3 | tu_trade_ng | |
127.0.0.1:7008 | nifa_db_t0 | tu_trade_ng |
nifa_db_t1 | tu_trade_ng | |
nifa_db_t2 | tu_trade_ng | |
nifa_db_t3 | tu_trade_ng | |
127.0.0.1:7009 | nifa_db_t0 | tu_trade_ng |
nifa_db_t1 | tu_trade_ng | |
nifa_db_t2 | tu_trade_ng | |
nifa_db_t3 | tu_trade_ng |
實現
mysql創建database
每個mysql實例中創建4個database,共計16個database:
CREATE DATABASE `nifa_db_t0` /*!40100 DEFAULT CHARACTER SET utf8 */;
CREATE DATABASE `nifa_db_t1` /*!40100 DEFAULT CHARACTER SET utf8 */;
CREATE DATABASE `nifa_db_t2` /*!40100 DEFAULT CHARACTER SET utf8 */;
CREATE DATABASE `nifa_db_t3` /*!40100 DEFAULT CHARACTER SET utf8 */;
mysql創建table
每個database中創建一個table,共計16個table:
# 複用了tu_trade_total_area_0的表結構
create table nifa_db_t0.tu_trade_ng like tu_trade_total_area_0;
create table nifa_db_t1.tu_trade_ng like tu_trade_total_area_0;
create table nifa_db_t2.tu_trade_ng like tu_trade_total_area_0;
create table nifa_db_t3.tu_trade_ng like tu_trade_total_area_0;
mycat制定
mycat需要配置的東西:
scheme.xml
<!-- 表名登記 以及分片規則、datanode關聯 -->
<table name="tu_trade_ng" primaryKey="ID" rule="certno-hashcode" dataNode="dnng$1-16" />
<!-- 16個datanode -->
<dataNode name="dn1" dataHost="NIFADB_1" database="nifa_db_t0" />
<dataNode name="dn2" dataHost="NIFADB_1" database="nifa_db_t1" />
<dataNode name="dn3" dataHost="NIFADB_1" database="nifa_db_t2" />
<dataNode name="dn4" dataHost="NIFADB_1" database="nifa_db_t3" />
<dataNode name="dn5" dataHost="NIFADB_2" database="nifa_db_t0" />
<dataNode name="dn6" dataHost="NIFADB_2" database="nifa_db_t1" />
<dataNode name="dn7" dataHost="NIFADB_2" database="nifa_db_t2" />
<dataNode name="dn8" dataHost="NIFADB_2" database="nifa_db_t3" />
<dataNode name="dn9" dataHost="NIFADB_3" database="nifa_db_t0" />
<dataNode name="dn10" dataHost="NIFADB_3" database="nifa_db_t1" />
<dataNode name="dn11" dataHost="NIFADB_3" database="nifa_db_t2" />
<dataNode name="dn12" dataHost="NIFADB_3" database="nifa_db_t3" />
<dataNode name="dn13" dataHost="NIFADB_4" database="nifa_db_t0" />
<dataNode name="dn14" dataHost="NIFADB_4" database="nifa_db_t1" />
<dataNode name="dn15" dataHost="NIFADB_4" database="nifa_db_t2" />
<dataNode name="dn16" dataHost="NIFADB_4" database="nifa_db_t3" />
<!-- 4個mysql實例 -->
<dataHost name="NIFADB_1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<writeHost host="NIFADB_HOST_M1" url="127.0.0.1:7006" user="dusername" password="password">
</writeHost>
</dataHost>
<dataHost name="NIFADB_2" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<writeHost host="NIFADB_HOST_M2" url="127.0.0.1:7007" user="dusername" password="password">
</writeHost>
</dataHost>
<dataHost name="NIFADB_3" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<writeHost host="NIFADB_HOST_M3" url="127.0.0.1:7008" user="dusername" password="password">
</writeHost>
</dataHost>
<dataHost name="NIFADB_4" maxCon="1000" minCon="10" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>show slave status</heartbeat>
<writeHost host="NIFADB_HOST_M4" url="127.0.0.1:7009" user="dusername" password="password">
< /writeHost>
</dataHost>
rule.xml
<!-- 分片規則 columns是table中的列名 algorithm是分片算法 -->
<tableRule name="certno-hashcode">
<rule>
<columns>certno</columns>
<algorithm>func_ng</algorithm>
</rule>
</tableRule>
<!-- 分片算法 partitionCount是我們要分的16個表 partitionCount*partitionLength=1024 -->
<!-- 注意1024是固定值,不能變!!! -->
<function name="func_ng" class="org.opencloudb.route.function.PartitionByLong">
<property name="partitionCount">16</property>
<property name="partitionLength">64</property>
</function>
說明:
使用mycat的固定分片hash 算法
,本條規則類似於十進制的求模運算,區別在於是二進制
的操作,是取id 的二進制低10 位,即id 二進制&1111111111。
此算法的優點在於如果按照10 進製取模運算,在連續插入1-10 時候1-10 會被分到1-10 個分片,增大了插入的事務控制難度,而此算法根據二進制則可能會分到連續
的分片,減少插入事務事務控制難度。
1024
是固定的,即最大支持1024 分區。
測試
# 插入121條數據 分了五個不等分的批次插入,插入10條到30條不等,每一條的certno字段都不一樣(每批次的certno在數字上連續)
insert into tu_trade_ng (NAME , CERTTYPE , CERTNO , ...... ) values ('餘崇天','0','110120199901012233',......);
# count總的數據量
select count(*) from tu_trade_ng;
+--------+
| COUNT0 |
+--------+
| 121 |
+--------+
# count每個table的數據量
+-----------+
| count(* ) |
+-----------+
| 60 | // dn1
| 1 | // dn2
| 0 | // dn3
| 0 | // dn4
| 1 | // dn5
| 0 | // dn6
| 0 | // dn7
| 0 | // dn8
| 1 | // dn9
| 1 | // dn10
| 9 | // dn11
| 0 | // dn12
| 1 | // dn13
| 2 | // dn14
| 25 | // dn15
| 20 | // dn16
+-----------+
測試說明了:
- 我們的分庫分表生效了,從mycat中查詢的數據量
等於
從mysql中分表查詢的數據量 固定分片hash 算法
的優點:算法根據二進制則可能會分到連續
的分片,減少插入事務事務控制難度
注意
mycat不支持insert into ... select ...
這種sql:
insert into tu_trade_ng (NAME , CERTTYPE , CERTNO , ......)
select NAME , CERTTYPE , CERTNO , ...... from an_old_table;
注意schema中的mysql實例賬號(下面的user
字段),要保證該賬號能訪問每一個tu_trade_ng表,不然使用mycat操作的tu_trade_ng會失敗:
<writeHost host="NIFADB_HOST_M3" url="127.0.0.1:7008" user="dusername" password="password">
以上實踐參考官方文檔。