水平拆分和垂直拆分
特性 | 垂直拆分 | 水平拆分 |
---|---|---|
概念 | 按照業(yè)務(wù)將表進行分類撒穷,將數(shù)據(jù)或者說壓力分擔到不同的庫匣椰。 | 按照某個字段的某種規(guī)則來分散到多個庫之中,每個表中包含一部分數(shù)據(jù)端礼。 |
優(yōu)點 | 拆分后業(yè)務(wù)清晰禽笑,拆分規(guī)則明確;系統(tǒng)之間整合或擴展容易蛤奥; 數(shù)據(jù)維護簡單佳镜。 | |
缺點 | 部分業(yè)務(wù)表無法join,只能通過接口方式解決凡桥,提高了系統(tǒng)復雜度蟀伸;受每種業(yè)務(wù)不同的限制存在單庫性能瓶頸,不易數(shù)據(jù)擴展跟性能提高缅刽;事務(wù)處理復雜啊掏。不能解決單表過于龐大的問題。 | |
共同缺點 | 引入分布式事務(wù)的問題拷恨;跨節(jié)點 Join 的問題脖律;跨節(jié)點合并排序分頁問題;多數(shù)據(jù)源管理問題 |
MyCat
Mycat 是一個強大的數(shù)據(jù)庫中間件腕侄。作用:讀寫分離小泉、分庫分表、容災(zāi)備份冕杠、多租戶應(yīng)用開發(fā)……
名稱 | 概念 |
---|---|
邏輯庫(schema) | 通常對實際應(yīng)用來說微姊,并不需要知道中間件的存在,業(yè)務(wù)開發(fā)人員只需要知道數(shù)據(jù)庫的概念分预,所以數(shù)據(jù)庫中間件可以被看做是一個或多個數(shù)據(jù)庫集群構(gòu)成的邏輯庫兢交。 |
邏輯表(table) | 邏輯表,可以是數(shù)據(jù)切分后笼痹,分布在一個或多個分片庫中配喳,也可以不做數(shù)據(jù)切分,不分片凳干,只有一個表構(gòu)成晴裹。 |
分片節(jié)點(datanNode) | 數(shù)據(jù)切分后,一個大表被分到不同的分片數(shù)據(jù)庫上面救赐,每個表分片所在的數(shù)據(jù)庫就是分片節(jié)點(dataNode)涧团。 |
節(jié)點主機(dataHost) | 數(shù)據(jù)切分后,每個分片節(jié)點(dataNode)不一定都會獨占一臺機器,同一機器上面可以有多個分片數(shù)據(jù)庫泌绣,這樣一個或多個分片節(jié)點(dataNode)所在的機器就是節(jié)點主機(dataHost),為了規(guī)避單節(jié)點主機并發(fā)數(shù)限制钮追,盡量將讀寫壓力高的分片節(jié)點(dataNode)均衡的放在不同的節(jié)點主機(dataHost)。 |
分片規(guī)則(rule) | |
全局序列號(sequence) | 數(shù)據(jù)唯一性標識 |
邏輯庫
邏輯表
- 分片表
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1,dn2" rule="rule1" />
- 非分片表
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1" />
ER 表
關(guān)系型數(shù)據(jù)庫是基于實體關(guān)系模型(Entity-Relationship Model)之上阿迈,通過其描述了真實世界中事物與關(guān)系元媚,Mycat 中的 ER 表即是來源于此。全局表
1)變動不頻繁仿滔;
2)數(shù)據(jù)量總體變化不大惠毁;
3)數(shù)據(jù)規(guī)模不大犹芹,很少有超過數(shù)十萬條記錄崎页。
全局表的配置,不用寫 rule 規(guī)則:
配置文件
配置文件 | 作用 |
---|---|
MYCAT_HOME/conf/schema.xml | 定義邏輯庫腰埂,表飒焦、分片節(jié)點等內(nèi)容; |
MYCAT_HOME/conf/rule.xml | 定義分片規(guī)則屿笼; |
MYCAT_HOME/conf/server.xml | 定義用戶以及系統(tǒng)相關(guān)變量牺荠,如端口等。 |
schema.xml
schema.xml 管理 MyCat 的邏輯庫驴一、表休雌、分片規(guī)則、DataNode 以及 DataSource肝断。
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" ></table>
</schema>
<schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="company" dataNode="dn10,dn11,dn12" rule="auto-sharding-long" ></table>
</schema>
schema 標簽的相關(guān)屬性
屬性名 | 值 | 定義 / 作用 |
---|---|---|
name | String | 用于綁定邏輯庫到某個具體的 database 上杈曲。1.3版本如果配置了dataNode,則不可以配置分片表胸懈,1.4 可以配置默認分片担扑,只需要配置需要分片的表 |
checkSQLschema | Boolean | 建議不帶這個字段,防止修改sql 語句趣钱。 |
sqlMaxLimit | Integer | 減少過多的數(shù)據(jù)返回 |
table 標簽
屬性 | 作用 |
---|---|
name | 定義邏輯表的表名涌献,這個名字就如同我在數(shù)據(jù)庫中執(zhí)行create table命令指定的名字一樣 |
dateNode | 定義邏輯表所屬 DataNode,該屬性的值需要和dataNode標簽中name屬性的值相互對應(yīng)首有。 |
rule | 規(guī)則名字燕垃,規(guī)則名字在 rule.xml 中定義,必須與 tableRule 標簽中 name 屬性屬性值一 一對應(yīng)井联。 |
ruleRequired | 指定表是否綁定分片規(guī)則卜壕,如果配置為true,但沒有配置具體rule的話低矮,程序會報錯 |
primaryKey | 邏輯表對應(yīng)真實表的主鍵 |
type | 類型印叁,分全局表(global)和普通表, |
autoIncrement | mysql對非自增長主鍵,使用last_insert_id()是不會返回結(jié)果的轮蜕,只會返回0昨悼。所以,只有定義了自增長主鍵的表才可以用last_insert_id()返回主鍵值跃洛。 |
subTables | 使用方式添加 subTables="t_order$1-2,t_order3"率触。目前分表 1.6 以后開始支持 并且 dataNode 在分表條件下只能配置一個,分表條件下不支持各種條件的join 語句汇竭。 |
needAddLimit | 表是否需要自動的在每個語句后面加上 limit 限制 |
dataNode 屬性
dn 過多可以使用如下方法減少配置
<table name="travelrecord" dataNode="multipleDn$0-99,multipleDn2$100-199" rule="auto-sharding?long" ></table>
<dataNode name="multipleDn$0-99" dataHost="localhost1" database="db$0-99" ></dataNode><dataNode name="multipleDn2$100-199" dataHost="localhost1" database=" db$100-199" ></dataNode>
childTable 標簽
用于定義 E-R 分片的子表葱蝗。通過標簽上的屬性與父表進行關(guān)聯(lián)。
屬性 | 值 | 定義/ 作用 |
---|---|---|
name | String | 定義子表的表名 |
joinKey | String | 插入子表的時候會使用這個列的值查找父表存儲的數(shù)據(jù)節(jié)點 |
parentKey | String | 屬性指定的值一般為與父表建立關(guān)聯(lián)關(guān)系的列名 |
primaryKey | String | 同 table 標簽所描述的 |
needAddLimit | boolean | 同 table 標簽所描述的 |
<table name="customer" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile">
<childTable name="orders" primaryKey="ID" joinKey="customer_id" parentKey="id">
<childTable name="order_items" joinKey="order_id" parentKey="id" /></childTable>
<childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" parentKey="id" />
</table>
dataNode 標簽
定義MyCat中的數(shù)據(jù)節(jié)點细燎,即數(shù)據(jù)分片两曼。
<dataNode name="dn1" dataHost="localhost1" database="db1" />
相關(guān)屬性
屬性名 | 值 | 定義 / 作用 |
---|---|---|
name | String | 數(shù)據(jù)節(jié)點的名字,這個名字需要是唯一的玻驻。 |
dataHost | String | 定義該分片屬于哪個數(shù)據(jù)庫實例的悼凑,屬性值是引用dataHost標簽上定義的name屬性。 |
database | String | 定義該分片屬于哪個具體數(shù)據(jù)庫實例上的具體庫 |
dataHost 標簽
定義了具體的數(shù)據(jù)庫實例璧瞬、讀寫分離配置和心跳語句户辫。
<dataHost name="localhost1" 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="localhost:3306" user="root" password="123456">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />
</writeHost>
<writeHost host="hostS1" url="localhost:3316" user="root" password="123456" />
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
屬性名 | 值 | 定義 / 作用 |
---|---|---|
name | String | 唯一標識dataHost 標簽 |
maxCon | Integer | 指定每個讀寫實例連接池的最大連接,也就是說,標簽內(nèi)嵌套的writeHost嗤锉、readHost 標簽都會使用這個屬性的值來實例化出連接池的最大連接數(shù) |
minCon | Integer | 指定每個讀寫實例連接池的最小連接渔欢,初始化連接池的大小。 |
balance | Integer | 負載均衡類型: 1. 指定每個讀寫實例連接池的最小連接瘟忱,初始化連接池的大小奥额。 2. balance="1",全部的readHost與stand by writeHost參與select語句的負載均衡酷誓,簡單的說披坏,當雙主雙從模式(M1->S1,M2->S2盐数,并且M1與M2互為主備)棒拂,正常情況下,M2,S1,S2都參與select語句的負載均衡玫氢。 3. balance="2"帚屉,所有讀操作都隨機的在writeHost、readhost 上分發(fā)漾峡。 4. balance="3"攻旦,所有讀請求隨機的分發(fā)到wiriterHost 對應(yīng)的readhost 執(zhí)行,writerHost 不負擔讀壓力生逸,注意balance=3只在1.4及其以后版本有牢屋,1.3沒有且预。 |
writeType | Integer | |
dbType | String | 指定后端連接的數(shù)據(jù)庫類型,目前支持二進制的mysql協(xié)議烙无,還有其他使用JDBC連接的數(shù)據(jù)庫锋谐。例如:mongodb、oracle截酷、spark 等涮拗。 |
dbDriver | String | 指定連接后端數(shù)據(jù)庫使用的Driver,目前可選的值有native和JDBC迂苛。使用native的話三热,因為這個值執(zhí)行的是二進制的mysql協(xié)議,所以可以使用mysql和maridb三幻。其他類型的數(shù)據(jù)庫則需要使用JDBC驅(qū)動來支持就漾。 |
heartbeat 標簽
這個標簽內(nèi)指明用于和后端數(shù)據(jù)庫進行心跳檢查的語句。例如,MYSQL可以使用select user()赌髓,Oracle可以使用select 1 from dual 等从藤。
1.4 主從切換的語句必須是:show slave status催跪。
writeHost標簽锁蠕、readHost標簽
這兩個標簽都指定后端數(shù)據(jù)庫的相關(guān)配置給mycat,用于實例化后端連接池懊蒸。唯一不同的是荣倾,writeHost 指定寫實例、readHost 指定讀實例骑丸,組著這些讀寫實例來滿足系統(tǒng)的要求舌仍。
在一個dataHost內(nèi)可以定義多個writeHost和readHost。但是通危,如果writeHost指定的后端數(shù)據(jù)庫宕機铸豁,那么這個writeHost綁定的所有readHost都將不可用。另一方面菊碟,由于這個writeHost宕機系統(tǒng)會自動的檢測到节芥,并切換到備用的writeHost 上去。
屬性名 | 值 | 定義 / 作用 |
---|---|---|
host | String | 用于標識不同實例逆害,一般writeHost我們使用M1头镊,readHost我們用S1。 |
url | String | 后端實例連接地址魄幕,例如 jdbc:mysql://localhost:3306/ |
user | String | 數(shù)據(jù)庫用戶名 |
password | String | 數(shù)據(jù)庫密碼 |
weight | String | 權(quán)重 |
usingDecrypt | String | 是否對密碼加密默認0 否如需要開啟配置1 |
schema.xml 完整展示
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<!-- 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="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
<!-- random sharding using mod sharind rule -->
<table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
rule="mod-long" />
<!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global"
needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3"
rule="mod-long" /> -->
<table name="employee" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile" />
<table name="customer" primaryKey="ID" dataNode="dn1,dn2"
rule="sharding-by-intfile">
<childTable name="orders" primaryKey="ID" joinKey="customer_id"
parentKey="id">
<childTable name="order_items" joinKey="order_id"
parentKey="id" />
</childTable>
<childTable name="customer_addr" primaryKey="ID" joinKey="customer_id"
parentKey="id" />
</table>
<!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
/> -->
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost1" database="db2" />
<dataNode name="dn3" dataHost="localhost1" database="db3" />
<!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
<dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
<dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" />
<dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> -->
<dataHost name="localhost1" 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="localhost:3306" user="root"
password="123456">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" />
</writeHost>
<writeHost host="hostS1" url="localhost:3316" user="root"
password="123456" />
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
<!--
<dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc">
<heartbeat> </heartbeat>
<writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" password="jifeng"></writeHost>
</dataHost>
<dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat>
<connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
<writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" password="123456" > </writeHost> </dataHost>
<dataHost name="jdbchost" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost>
<dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc">
<heartbeat> </heartbeat>
<writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" password="jifeng"></writeHost> </dataHost> -->
<!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql"
dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1"
url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost>
</dataHost> -->
</mycat:schema>
server.xml
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">TESTDB</property>
<!-- 表級 DML 權(quán)限設(shè)置 -->
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
</user>
全局表一致性檢查 和 分布式事務(wù)開關(guān)都在 server.xml 配置相艇。
rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="rule1">
<rule>
<columns>id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<tableRule name="rule2">
<rule>
<columns>user_id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-intfile">
<rule>
<columns>sharding_id</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-murmur">
<rule>
<columns>id</columns>
<algorithm>murmur</algorithm>
</rule>
</tableRule>
<tableRule name="crc32slot">
<rule>
<columns>id</columns>
<algorithm>crc32slot</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-month">
<rule>
<columns>create_time</columns>
<algorithm>partbymonth</algorithm>
</rule>
</tableRule>
<tableRule name="latest-month-calldate">
<rule>
<columns>calldate</columns>
<algorithm>latestMonth</algorithm>
</rule>
</tableRule>
<tableRule name="auto-sharding-rang-mod">
<rule>
<columns>id</columns>
<algorithm>rang-mod</algorithm>
</rule>
</tableRule>
<tableRule name="jch">
<rule>
<columns>id</columns>
<algorithm>jump-consistent-hash</algorithm>
</rule>
</tableRule>
<function name="murmur"
class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!-- 默認是0 -->
<property name="count">2</property><!-- 要分片的數(shù)據(jù)庫節(jié)點數(shù)量篇恒,必須指定姚糊,否則沒法分片 -->
<property name="virtualBucketTimes">160</property><!-- 一個實際的數(shù)據(jù)庫節(jié)點被映射為這么多虛擬節(jié)點玲献,默認是160倍,也就是虛擬節(jié)點數(shù)是物理節(jié)點數(shù)的160倍 -->
<!-- <property name="weightMapFile">weightMapFile</property> 節(jié)點的權(quán)重攘须,沒有指定權(quán)重的節(jié)點默認是1。以properties文件的格式填寫呢堰,以從0開始到count-1的整數(shù)值也就是節(jié)點索引為key屿聋,以節(jié)點權(quán)重值為值。所有權(quán)重值必須是正整數(shù)臭墨,否則以1代替 -->
<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
用于測試時觀察各物理節(jié)點與虛擬節(jié)點的分布情況赔嚎,如果指定了這個屬性,會把虛擬節(jié)點的murmur hash值與物理節(jié)點的映射按行輸出到這個文件胧弛,沒有默認值尤误,如果不指定,就不會輸出任何東西 -->
</function>
<function name="crc32slot"
class="io.mycat.route.function.PartitionByCRC32PreSlot">
</function>
<function name="hash-int"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
<function name="func1" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">8</property>
<property name="partitionLength">128</property>
</function>
<function name="latestMonth"
class="io.mycat.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property>
</function>
<function name="partbymonth"
class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2015-01-01</property>
</function>
<function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
<property name="mapFile">partition-range-mod.txt</property>
</function>
<function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
<property name="totalBuckets">3</property>
</function>
</mycat:rule>
tableRule 標簽
這個標簽定義表規(guī)則结缚。定義的表規(guī)則损晤,在 schema.xml:
<tableRule name="sharding-by-intfile">
<rule>
<columns>sharding_id</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
name 屬性指定唯一的名字,用于標識不同的表規(guī)則红竭。
內(nèi)嵌的 rule 標簽則指定對物理表中的哪一列進行拆分和使用什么路由算法尤勋。
columns 內(nèi)指定要拆分的列名字。
algorithm 使用 function 標簽中的 name 屬性茵宪。連接表規(guī)則和具體路由算法最冰。當然,多個表規(guī)則可以連接到
同一個路由算法上稀火。table 標簽內(nèi)使用暖哨。讓邏輯表使用這個規(guī)則進行分片。
function 標簽
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
name 指定算法的名字凰狞。
class 制定路由算法具體的類名字篇裁。
property 為具體算法需要用到的一些屬性。
Mycat 的分片 join
INNER JOIN
內(nèi)連接赡若,也叫等值連接达布,inner join 產(chǎn)生同時符合A表和B表的一組數(shù)據(jù)。
LEFT JOIN
左連接從A表(左)產(chǎn)生一套完整的記錄逾冬,與匹配的 B 表記錄(右表) 黍聂,如果沒有匹配,右側(cè)將包含 null粉渠。
right join 與之相反分冈。 full join:全連接產(chǎn)生的所有記錄(雙方匹配記錄)在表A和表B。如果沒有匹配,則對面將包含 null霸株。
性能建議
盡量避免使用 Left join 或 Right join雕沉,而用 Inner join;
在使用 左右連接時去件,ON 會優(yōu)先執(zhí)行坡椒,where 條件在最后執(zhí)行扰路,所以在使用過程中,條件盡可能的在 ON 語句中判斷倔叼,減少 where 的執(zhí)行汗唱;
少用子查詢,而用 join丈攒。
全局表
字典表特性:
- 變動不頻繁哩罪,可以根據(jù)主鍵 ID 進行緩存
- 數(shù)據(jù)量總體變化不大
- 數(shù)據(jù)規(guī)模不大,很少有超過數(shù)十萬條記錄巡验。
鑒于此际插,MyCAT 定義了一種特殊的表,稱之為“全局表”显设,全局表具有以下特性:
- 全局表的插入框弛、更新操作會實時在所有節(jié)點上執(zhí)行,保持各個分片的數(shù)據(jù)一致性
- 全局表的查詢操作捕捂,只從一個節(jié)點獲取
- 全局表可以跟任何一個表進行 JOIN 操作
通過全局表+基于 E-R 關(guān)系的分片策略瑟枫,MyCAT 可以滿足 80%以上的企業(yè)應(yīng)用開發(fā),全局表配置簡單指攒,不用寫 rule 規(guī)則慷妙。
<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
ER join
基于 E-R 關(guān)系的數(shù)據(jù)分片策略。配置如下:
<table name="customer" dataNode="dn1,dn2" rule="sharding-by-intfile">
<childTable name="orders" joinKey="customer_id" parentKey="id"/>
</table>
share join
目前支持 2 個表的 join,原理就是解析 SQL 語句幽七,拆分成單表的 SQL 語句執(zhí)行景殷,然后把各個節(jié)點的數(shù)據(jù)匯集。
<!-- A,B 的 dataNode 相同-->
<table name="A" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<table name="B" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<!-- A,B 的 dataNode 不同-->
<table name="A" dataNode="dn1,dn2 " rule="auto-sharding-long" />
<table name="B" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<!-- 或者-->
<table name="A" dataNode="dn1 " rule="auto-sharding-long" />
<table name="B" dataNode=" dn2,dn3" rule="auto-sharding-long" />
/*!mycat:catlet=io.mycat.catlets.ShareJoin*/select * from employee a, employee_detail b where a.id = b.id;
人工智能
p 104
MyCat 常用的分片規(guī)則
分片枚舉
通過在配置文件中配置可能的枚舉 id澡屡,自己配置分片,本規(guī)則適用于特定的場景咐旧,比如有些業(yè)務(wù)需要按照省份或區(qū)縣來做保存驶鹉,而全國省份區(qū)縣固定的,這類業(yè)務(wù)使用本條規(guī)則铣墨,配置如下:
<tableRule name="sharding-by-intfile">
<rule>
<columns>user_id</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">0</property>
<property name="defaultNode">0</property>
</function>
partition-hash-int.txt 配置:
10000=0
10010=1
DEFAULT_NODE=1
固定分片 hash 算法
此算法的優(yōu)點在于如果按照 10 進制取模運算室埋,在連續(xù)插入 1-10 時候,1-10 會被分到 1-10 個分片伊约,增大了插入的事務(wù)控制難度姚淆,而此算法根據(jù)二進制則可能會分到連續(xù)的分片,減少插入的事務(wù)控制難度屡律。
<tableRule name="rule1">
<rule>
<columns>user_id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<function name="func1" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">2,1</property>
<property name="partitionLength">256,512</property>
</function>
配置說明:
上面 columns 標識將要分片的表字段腌逢,algorithm 分片函數(shù),
partitionCount 分片個數(shù)列表超埋,partitionLength 分片范圍列表
分區(qū)長度:默認為最大 2^n=1024 ,即最大支持 1024 分區(qū)
**約 束 : **
count,length 兩個數(shù)組的長度必須是一致的搏讶。
范圍約定
適用提前規(guī)劃好分片字段某個范圍屬于哪個分片
<tableRule name="auto-sharding-long">
<rule>
<columns>user_id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
<property name="defaultNode">0</property>
</function>
配置說明:
上面 columns 標識將要分片的表字段佳鳖,algorithm 分片函數(shù),
rang-long 函數(shù)中 mapFile 代表配置文件路徑
defaultNode 超過范圍后的默認節(jié)點媒惕。
autopartition-long.txt:
# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2
取模
<tableRule name="mod-long">
<rule><columns>user_id</columns>
<algorithm>mod-long</algorithm></rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!--how manydatanodes-->
<property name="count">3</property>
</function>
配置說明:
上面columns 標識將要分片的表字段系吩,algorithm 分片函數(shù),rang-long 函數(shù)中mapFile 代表配置文件路徑defaultNode 超過范圍后的默認節(jié)點妒蔚。所有的節(jié)點配置都是從0開始穿挨,及0代表節(jié)點1,此配置非常簡單肴盏,即預(yù)先制定可能的id范圍到某個分片
按日期(天)分片
非重點
取模范圍約束
此種規(guī)則是取模運算與范圍約束的結(jié)合絮蒿,主要為了后續(xù)數(shù)據(jù)遷移做準備,即可以自主決定取模后數(shù)據(jù)的節(jié)點分布叁鉴。
<tableRule name="sharding-by-pattern">
<rule>
<columns>user_id</columns>
<algorithm>sharding-by-pattern</algorithm>
</rule>
</tableRule>
<function name="sharding-by-pattern" class="io.mycat.route.function.PartitionByPattern">
<property name="patternValue">256</property>
<property name="defaultNode">2</property>
<property name="mapFile">partition-pattern.txt</property>
</function>
partition-pattern.txt
# id partition range start-end ,data node index
###### first host configuration
1-32=0
33-64=1
65-96=2
97-128=3
######## second host configuration
129-160=4
161-192=5
193-224=6
225-256=7
0-0=7
配置說明:
上面columns 標識將要分片的表字段土涝,algorithm 分片函數(shù),patternValue 即求幕夏梗基數(shù)但壮,defaoultNode 默認節(jié)點,如果配置了默認常侣,則不會按照求模運算
mapFile 配置文件路徑
配置文件中蜡饵,1-32即代表id%256后分布的范圍,如果在1-32則在分區(qū)1胳施,其他類推溯祸,如果id非數(shù)據(jù),則會分配在defaoultNode默認節(jié)點
String idVal = “0”;
Assert.assertEquals(true, 7 == autoPartition.calculate(idVal));
idVal = “45a”;
Assert.assertEquals(true, 2 == autoPartition.calculate(idVal));
截取數(shù)字做hash 求模范圍約束
后續(xù)補
應(yīng)用指定
后續(xù)補
截取數(shù)字hash 解析
后續(xù)補
一致性hash(重點)
一致性hash 預(yù)算有效解決了分布式數(shù)據(jù)的擴容問題舞肆。
<tableRule name="sharding-by-murmur">
<rule>
<columns>user_id</columns>
<algorithm>murmur</algorithm>
</rule>
</tableRule>
<function name="murmur" class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!--默認是0-->
<property name="count">2</property><!--要分片的數(shù)據(jù)庫節(jié)點數(shù)量焦辅,必須指定,否則沒法分片-->
<property name="virtualBucketTimes">160</property><!--一個實際的數(shù)據(jù)庫節(jié)點被映射為這么多虛擬節(jié)點椿胯,默認是160倍筷登,也就是虛擬節(jié)點數(shù)是物理節(jié)點數(shù)的160倍-->
<!--<property name="weightMapFile">weightMapFile</property>節(jié)點的權(quán)重,沒有指定權(quán)重的節(jié)點默認是1哩盲。以properties文件的格式填寫前方,以從0開始到count-1的整數(shù)值也就是節(jié)點索引為key,以節(jié)點權(quán)重值為值廉油。所有權(quán)重值必須是正整數(shù)惠险,否則以1代替-->
<!--<property name="bucketMapPath">/etc/mycat/bucketMapPath</property>用于測試時觀察各物理節(jié)點與虛擬節(jié)點的分布情況,如果指定了這個屬性抒线,會把虛擬節(jié)點的murmur hash值與物理節(jié)點的映射按行輸出到這個文件班巩,沒有默認值,如果不指定十兢,就不會輸出任何東西-->
</function>
范圍求模分片(重點)
先進行范圍分片計算出分片組趣竣,組內(nèi)再求模優(yōu)點可以避免擴容時的數(shù)據(jù)遷移摇庙,又可以一定程度上避免范圍分片的熱點問題綜合了范圍分片和求模分片的優(yōu)點,分片組內(nèi)使用求囊B疲可以保證組內(nèi)數(shù)據(jù)比較均勻卫袒,分片組之間是范圍分片可以兼顧范圍查詢。
最好事先規(guī)劃好分片的數(shù)量单匣,數(shù)據(jù)擴容時按分片組擴容夕凝,則原有分片組的數(shù)據(jù)不需要遷移。由于分片組內(nèi)數(shù)據(jù)比較均勻户秤,所以分片組內(nèi)可以避免熱點數(shù)據(jù)問題码秉。
<tableRule name="auto-sharding-rang-mod">
<rule>
<columns>id</columns>
<algorithm>rang-mod</algorithm>
</rule>
</tableRule>
<function name="rang-mod"class="io.mycat.route.function.PartitionByRangeMod">
<property name="mapFile">partition-range-mod.txt</property>
<property name="defaultNode">21</property>
</function>
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數(shù)鸡号,rang-mod 函數(shù)中mapFile 代表配置文件路徑defaultNode 超過范圍后的默認節(jié)點順序號转砖,節(jié)點從0 開始。
partition-range-mod.txt
range start-end ,data node group size
以下配置一個范圍代表一個分片組鲸伴,=號后面的數(shù)字代表該分片組所擁有的分片的數(shù)量府蔗。
partition-range-mod.txt
# range start-end ,data node group size
0-200M=5
200M1-400M=1
400M1-600M=4
600M1-800M=4
800M1-1000M=6
還有幾種不常用,就不介紹了汞窗。
配置支持 Oracle
<dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle"
dbDriver="jdbc">
<heartbeat>select 1 from dual</heartbeat>
<connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
<writeHost host="hostM1" url="jdbc:oracle:thin:@192.168.0.95:1521:orcl" user="test" password="test" ></writeHost>
</dataHost>
- dbDriver 一定為 jdbc,dbType 代表數(shù)據(jù)庫類型姓赤,可以為 mysql,oracle,mongodb
- url 地址是 jdbc 連接的地址,和一般開發(fā) java web 的 jdbc.url 地址一致,user,password 是用戶名和密碼
- 是心跳包的查詢語句
- 是連接 oracle 的初始化語句,初始化本次會話的日期顯示格式
- 需要 ojdbc14-x.jar 包(其它版本也支持)
MyCat 分頁查詢解決
mycat 對多數(shù)據(jù)庫分頁語法的支持主要分為 2 種方式:
一是 limit 語法自動轉(zhuǎn)換成原生分頁語法仲吏;
二是直接支持對原生分頁語句不铆。目前支持的數(shù)據(jù)庫分頁的類型有 oracle、db2裹唆、sqlserver誓斥、PostgreSQL 等。
DruidMycatRouteStrategy 路由策略入口
MycatStatementParser 擴展語句解析
MycatSelectParser 擴展查詢語句解析
MycatExprParser 擴展支持聚合函數(shù)
MycatLexer 擴展支持關(guān)鍵詞
DruidParserFactory 解析工廠類
DruidSelectOracleParser oracle 分頁解析
DruidSelectDb2Parser db2 分頁解析
DruidSelectSqlServerParser sqlserver 分頁解析
DruidSelectPostgresqlParser PostgreSQL 分頁支持
RouteResultset 路由結(jié)果類
MyBatis PageHelper
https://blog.csdn.net/itcats_cn/article/details/81586724
Mybatis的插件運行原理
Mybatis僅可以編寫針對ParameterHandler品腹、ResultSetHandler岖食、StatementHandler、Executor這4種接口的插件舞吭,Mybatis使用JDK的動態(tài)代理,為需要攔截的接口生成代理對象以實現(xiàn)接口方法攔截功能析珊,每當執(zhí)行這4種接口對象的方法時羡鸥,就會進入攔截方法,具體就是InvocationHandler的invoke()方法忠寻,當然惧浴,只會攔截那些你指定需要攔截的方法。