MyCat 總結(jié)葫督,看完這篇帶你了解分庫分表

水平拆分和垂直拆分

特性 垂直拆分 水平拆分
概念 按照業(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ā)……

數(shù)據(jù)庫中間件
名稱 概念
邏輯庫(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ù)。

內(nèi)連接

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>
  1. dbDriver 一定為 jdbc,dbType 代表數(shù)據(jù)庫類型姓赤,可以為 mysql,oracle,mongodb
  2. url 地址是 jdbc 連接的地址,和一般開發(fā) java web 的 jdbc.url 地址一致,user,password 是用戶名和密碼
  3. 是心跳包的查詢語句
  4. 是連接 oracle 的初始化語句,初始化本次會話的日期顯示格式
  5. 需要 ojdbc14-x.jar 包(其它版本也支持)

MyCat 分頁查詢解決

mycat 對多數(shù)據(jù)庫分頁語法的支持主要分為 2 種方式:
一是 limit 語法自動轉(zhuǎn)換成原生分頁語法仲吏;
二是直接支持對原生分頁語句不铆。目前支持的數(shù)據(jù)庫分頁的類型有 oracle、db2裹唆、sqlserver誓斥、PostgreSQL 等。

  1. DruidMycatRouteStrategy 路由策略入口

  2. MycatStatementParser 擴展語句解析

  3. MycatSelectParser 擴展查詢語句解析

  4. MycatExprParser 擴展支持聚合函數(shù)

  5. MycatLexer 擴展支持關(guān)鍵詞

  6. DruidParserFactory 解析工廠類

  7. DruidSelectOracleParser oracle 分頁解析

  8. DruidSelectDb2Parser db2 分頁解析

  9. DruidSelectSqlServerParser sqlserver 分頁解析

  10. DruidSelectPostgresqlParser PostgreSQL 分頁支持

  11. 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()方法忠寻,當然惧浴,只會攔截那些你指定需要攔截的方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奕剃,一起剝皮案震驚了整個濱河市衷旅,隨后出現(xiàn)的幾起案子捐腿,更是在濱河造成了極大的恐慌,老刑警劉巖柿顶,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茄袖,死亡現(xiàn)場離奇詭異,居然都是意外死亡嘁锯,警方通過查閱死者的電腦和手機宪祥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來家乘,“玉大人蝗羊,你說我怎么就攤上這事∪示猓” “怎么了耀找?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長业崖。 經(jīng)常有香客問我野芒,道長,這世上最難降的妖魔是什么腻要? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任复罐,我火速辦了婚禮,結(jié)果婚禮上雄家,老公的妹妹穿的比我還像新娘效诅。我一直安慰自己,他們只是感情好趟济,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布乱投。 她就那樣靜靜地躺著,像睡著了一般顷编。 火紅的嫁衣襯著肌膚如雪戚炫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天媳纬,我揣著相機與錄音双肤,去河邊找鬼。 笑死钮惠,一個胖子當著我的面吹牛茅糜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播素挽,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔑赘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缩赛,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤耙箍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后酥馍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辩昆,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年物喷,在試婚紗的時候發(fā)現(xiàn)自己被綠了卤材。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡峦失,死狀恐怖扇丛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尉辑,我是刑警寧澤帆精,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站隧魄,受9級特大地震影響卓练,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜购啄,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一襟企、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狮含,春花似錦顽悼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至映胁,卻和暖如春木羹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背解孙。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工坑填, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弛姜。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓穷遂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親娱据。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容