share join:分片表 join
目錄
零:分片表實操
ShareJoin 是一個簡單的跨分片 Join,目前支持 2 個表的 join,原理就是解析 SQL 語句,拆分成單表的 SQL 語句執行,然後把各個節點的數據彙集。有限制,不同分盤規則最多兩表操作
受限制的原因主要在於:各表的分片後的數據可能不在同一個分片中。所以會導致問題。
特殊情況:多個表使用同一種分片規則,且分片規則屬性相同。在 share join 可以支持多與兩表的查詢。以下是測試樣例:
schemel.xml,注意點就是我添加了兩個範圍分片的表 wyptable lxjtable
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="mydb" checkSQLschema="true" sqlMaxLimit="100">
<table name="lsqtable" primaryKey="id" autoIncrement="true" dataNode="dn$1-2" rule="mod-long" >
<childTable name="lsqtable_supplement" primaryKey="id" joinKey="id" parentKey="id" >
<childTable name="lsqtable_supplement_items" joinKey="parent_id" parentKey="id" />
</childTable>
<childTable name="lsqtable_supplement_other" primaryKey="id" joinKey="id" parentKey="id" />
</table>
<table name="wyptable" primaryKey="id" autoIncrement="true" dataNode="dn$1-2" rule="auto-sharding-long" />
<table name="lxjtable" primaryKey="id" autoIncrement="true" dataNode="dn$1-2" rule="auto-sharding-long" />
<table name="jointable" primaryKey="id" type="global" autoIncrement="true" dataNode="dn$1-2" />
<table name="otherjointable" primaryKey="id" type="global" autoIncrement="true" dataNode="dn$1-2" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="mydb" />
<dataNode name="dn2" dataHost="localhost2" database="mydb" />
</mycat:schema>
表名 | 所屬節點 | 切分列 | 切分規則 |
lsqtable | dn$1-2 | id | mod-long 取模 |
lsqtable_supplement | dn$1-2 | id | 繼承 ER 父類切分規則 mod-long |
lsqtable_supplement_items | dn$1-2 | parent_id | 繼承 ER 父類切分規則 mod-long |
lsqtable_supplement_other | dn$1-2 | id | 繼承 ER 父類切分規則 mod-long |
wyptable | dn$1-2 | id |
auto-sharding-long 範圍分片,但是範圍 給的很大,數據都被路由到 dn1 中 |
lxjtable | dn$1-2 | id |
auto-sharding-long 範圍分片,但是範圍 給的很大,數據都被路由到 dn1 中 |
jointable | dn$1-2 | id | global 全局表,路由到所有節點插入 |
otherjointable | dn$1-2 | id | global 全局表,路由到所有節點插入 |
查詢條件如下:
表 lxjtable 和 wyptable 進行關聯查詢,可以查詢且可以查詢到執行計劃,因爲新添加的兩個表使用的同種切分規則,且規則一致。(多個表沒試,想使用的小夥伴可以試下)
EXPLAIN SELECT *
FROM lxjtable lxj
INNER JOIN wyptable wyp ON lxj.id = wyp.id
dn1 SELECT * FROM lxjtable lxj INNER JOIN wyptable wyp ON lxj.id = wyp.id
dn2 SELECT * FROM lxjtable lxj INNER JOIN wyptable wyp ON lxj.id = wyp.id
如果兩個不同切分規則的表進行 join 就會觸發 share join 操作,不能查出查詢計劃。如 lsqtable 和 lxjtable 兩表,無執行計劃,只有結果集。但是仍可以聯查全局表。
EXPLAIN SELECT *
FROM lxjtable lxj
INNER JOIN lsqtable lsq ON lxj.id = lsq.id
從日誌中可以看出 cat.log
INFO [$_NIOREACTOR-5-RW] (io.mycat.catlets.JoinParser.parserTable(JoinParser.java:101)) - table lsqtable Alias:lsq Hints:[]
INFO [$_NIOREACTOR-5-RW] (io.mycat.catlets.JoinParser.parser(JoinParser.java:79)) - SQL: SELECT * FROM lxjtable lxj INNER JOIN lsqtable lsq ON lxj.id = lsq.id
INFO [$_NIOREACTOR-5-RW] (io.mycat.catlets.ShareJoin.processSQL(ShareJoin.java:172)) - Catlet exec:dn1,dn2, sql:select *, id from lxjtable
INFO [$_NIOREACTOR-0-RW] (io.mycat.cache.DefaultLayedCachePool.createChildCache(DefaultLayedCachePool.java:80)) - create child Cache: mydb_LSQTABLE for layered cache TableID2DataNodeCache, size 10000, expire seconds 18000
INFO [$_NIOREACTOR-0-RW] (io.mycat.catlets.ShareJoin.createQryJob(ShareJoin.java:275)) - SQLParallJob:dn1,dn2, sql:select * from lsqtable where id in (1,2)
INFO [$_NIOREACTOR-5-RW] (io.mycat.sqlengine.EngineCtx.onJobFinished(EngineCtx.java:194)) - all job finished for front connection: ServerConnection [id=1, schema=mydb, host=0:0:0:0:0:0:0:1, user=root,txIsolation=3, autocommit=true, schema=mydb]
INFO [$_NIOREACTOR-5-RW] (io.mycat.sqlengine.EngineCtx.writeEof(EngineCtx.java:180)) - write eof ,packgId:13
INFO [$_NIOREACTOR-5-RW] (io.mycat.catlets.ShareJoin$1.onAllJobFinished(ShareJoin.java:189)) - 發送數據OK
INFO [$_NIOREACTOR-5-RW] (io.mycat.catlets.JoinParser.parserTable(JoinParser.java:101)) - table lsqtable Alias:lsq Hints:[]
INFO [$_NIOREACTOR-5-RW] (io.mycat.catlets.JoinParser.parser(JoinParser.java:79)) - SQL: SELECT * FROM lxjtable lxj INNER JOIN lsqtable lsq ON lxj.id = lsq.id
INFO [$_NIOREACTOR-5-RW] (io.mycat.catlets.ShareJoin.processSQL(ShareJoin.java:172)) - Catlet exec:dn1,dn2, sql:select *, id from lxjtable
INFO [$_NIOREACTOR-4-RW] (io.mycat.catlets.ShareJoin.createQryJob(ShareJoin.java:275)) - SQLParallJob:dn1,dn2, sql:select * from lsqtable where id in (1,2)
INFO [$_NIOREACTOR-0-RW] (io.mycat.sqlengine.EngineCtx.onJobFinished(EngineCtx.java:194)) - all job finished for front connection: ServerConnection [id=1, schema=mydb, host=0:0:0:0:0:0:0:1, user=root,txIsolation=3, autocommit=true, schema=mydb]
INFO [$_NIOREACTOR-0-RW] (io.mycat.sqlengine.EngineCtx.writeEof(EngineCtx.java:180)) - write eof ,packgId:13
INFO [$_NIOREACTOR-0-RW] (io.mycat.catlets.ShareJoin$1.onAllJobFinished(ShareJoin.java:189)) - 發送數據OK
比較重要的點:基本上就是將 A share join B 的操作,分爲兩部分左側查詢和右側查詢,左表 select *, id 右側 select * in 操作。之後根據左側的 id 替換右側的結果集,合併數據。
Catlet exec:dn1,dn2, sql:select *, id from lxjtable
SQLParallJob:dn1,dn2, sql:select * from lsqtable where id in (1,2)
且三表聯查時將發生錯誤。如下。
EXPLAIN SELECT *
FROM lxjtable lxj
INNER JOIN lsqtable lsq ON lxj.id = lsq.id
INNER JOIN wyptable wyp ON lxj.id = wyp.id
> 2013 - Lost connection to MySQL server during query
> 時間: 0.02s
但是關聯多個全局表是可以的。
其實就是,不過多少個表,只要是以相同的分片規則分在一個節點(全局表每個節點冗餘),每個分片都可以自主的進行數據關聯,之後進行合併。但是以不同分片規則的表就不一樣了。因爲相關聯的節點可能處在不同的節點中。這樣只能先按分片鍵查出第一個表的相關數據。之後使用 in 關鍵字來查第二個表。所以最好在第一個表查詢時加入 on 關鍵字來降低第一個結果集的數量。