Mycat跨分片Join


  

1 前言

Mycat目前版本支持跨分片的join,主要實現的方式有四種。

全局表

ER分片

HBT(參考MyCAT人工智能解決跨分片SQL.docx)

ShareJoin

ShareJoin在開發版中支持,前面三種方式1.3.0.1支持

2 ShareJoin

   ShareJoin是一個簡單的跨分片Join,基於HBT的方式實現。

目前支持2個表的join,原理就是解析SQL語句,拆分成單表的SQL語句執行,然后把各個節點的數據匯集。

支持任意配置的A,B表

如:

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" />

2.1相關類圖

 

JoinParser: SQL語句的解析

TableFilter:存解析后的各個子表

ShareJoin:執行拆分的語句管理控制,和字段,記錄的管理

ShareDBJoinHandler:第一個表執行后獲取數據的handler

ShareRowOutPutDataHandler:最后一個表執行后獲取數據的handler

 

EnginerCtx:執行引擎

SQLJob:SQL語句執行任務

SQLJobHandler:SQL語句執行后獲取數據的handler

BatchSQLJob:批量執行任務控制

AllJobFinishedListener:所有任務完成偵聽器

RouteService-----》HintCatletHandler---》ShareJoin


 

2.1測試

默認mycat的環境測試:

 

/*!mycat:catlet=demo.catlets.ShareJoin */ select a.*,b.id, b.name as tit from customer a,company b on a.company_id=b.id;

 

/*!mycat:catlet=demo.catlets.ShareJoin */ select a.*,b.id, b.name as name from orders a join customer b where a.customer_id=b.id;

 

/*!mycat:catlet=demo.catlets.ShareJoin */ select a.*,b.* from orders a join customer b where a.customer_id=b.id;

 

/*!mycat:catlet=demo.catlets.ShareJoin */ select a.id,a.user_id,a.traveldate,a.fee,a.days,b.id as nnid, b.title as tit from travelrecord  a  join  hotnews b on b.id=a.days order by a.id ;

 

 

2.3升級

未來支持多表的跨分片Join

小表放人緩存或廣播方式

 

3全局表

一個真實的業務系統中,往往存在大量的類似字典表的表格,它們與業務表之間可能有關系,這種關系,可以理解為“標簽”,而不應理解為通常的“主從關系”,這些表基本上很少變動,可以根據主鍵ID進行緩存,下面這張圖說明了一個典型的“標簽關系”圖:

 

         在分片的情況下,當業務表因為規模而進行分片以后,業務表與這些附屬的字典表之間的關聯,就成了比較棘手的問題,考慮到字典表具有以下幾個特性:

  • 變動不頻繁
  • 數據量總體變化不大
  • 數據規模不大,很少有超過數十萬條記錄。

鑒於此,MyCAT定義了一種特殊的表,稱之為“全局表”,全局表具有以下特性:

  • 全局表的插入、更新操作會實時在所有節點上執行,保持各個分片的數據一致性
  • 全局表的查詢操作,只從一個節點獲取
  • 全局表可以跟任何一個表進行JOIN操作

將字典表或者符合字典表特性的一些表定義為全局表,則從另外一個方面,很好的解決了數據JOIN的難題。通過全局表+基於E-R關系的分片策略,MyCAT可以滿足80%以上的企業應用開發。

 

3.1配置

全局表配置比較簡單,不用寫Rule規則,如下配置即可:

<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />

需要注意的是,全局表每個分片節點上都要有運行創建表的DDL語句。

 

4ER分片

MyCAT借鑒了NewSQL領域的新秀Foundation DB的設計思路,Foundation DB創新性的提出了Table Group的概念,其將子表的存儲位置依賴於主表,並且物理上緊鄰存放,因此徹底解決了JION的效率和性能問題,根據這一思路,提出了基於E-R關系的數據分片策略,子表的記錄與所關聯的父表記錄存放在同一個數據分片上。

customer采用sharding-by-intfile這個分片策略,分片在dn1,dn2上,orders依賴父表進行分片,兩個表的關聯關系為orders.customer_id=customer.id。於是數據分片和存儲的示意圖如下:

這樣一來,分片Dn1上的的customer與Dn1上的orders就可以進行局部的JOIN聯合,Dn2上也如此,再合並兩個節點的數據即可完成整體的JOIN,試想一下,每個分片上orders表有100萬條,則10個分片就有1個億,基於E-R映射的數據分片模式,基本上解決了80%以上的企業應用所面臨的問題。

 

4.1     配置

以上述例子為例,schema.xml中定義如下的分片配置:

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

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

</table>

5HBT分片

解決跨分片的SQL JOIN的問題,遠比想象的復雜,而且往往無法實現高效的處理,既然如此,就依靠人工的智力,去編程解決業務系統中特定幾個必須跨分片的SQL的JOIN邏輯,MyCAT提供特定的API供程序員調用,這就是MyCAT創新性的思路——人工智能。

以一個跨節點的SQL為例,

Select a.id,a.name,b.title from a,b where a.id=b.id

         其中a在分片1,2,3上,b在4,5,6上,需要把數據全部拉到本地(MyCAT服務器),執行JOIN邏輯,具體過程如下(只是一種可能的執行邏輯):

 

EngineCtx ctx=new EngineCtx();//包含MyCat.SQLEngine

String sql=,“select a.id ,a.name from a ”;

//在a表所在的所有分片上順序執行下面的本地SQL

ctx.executeNativeSQLSequnceJob(allAnodes,new DirectDBJoinHandler());

DirectDBJoinHandler類是一個回調類,負責處理SQL執行過程中返回的數據包,這里的這個類,主要目的是用a表返回的ID信息,去b表上查詢對於的記錄,做實時的關聯:

DirectDBJoinHandler{

  Private HashMap<byte[],byte[]> rows;//Key為id,value為一行記錄的Column原始Byte數組,這里是a.id,a.name,b.title這三個要輸出的字段

   Public Boolean onHeader(byte[] header)

//保存Header信息,用於從Row中獲取Field字段值

}

   Public Boolean onRowData(byte[] rowData)

{

    String id=getColumnAsString(“id”);

//放入結果集,b.title字段未知,所以先空着

rows.put(getColumnRawBytes(“id”),rowData);

  //滿1000條,發送一個查詢請求

String sql=”select b.id, b.name  from b where id in (………….)”;

 

//此SQL在B的所有節點上並發執行,返回的結果直接輸出到客戶端

 ctx.executeNativeSQLParallJob(allBNodes,sql ,new MyRowOutPutDataHandler(rows));

 

}

   Public Boolean onRowFinished()

  {

 }

Public void onJobFinished()

 {

If(ctx.allJobFinished())

     {///used total time ….

 

     }

}

}

/最后,增加一個Job事件監聽器,這里是所有Job完成后,往客戶端發送RowEnd包,結束整個流程。

ctx.setJobEventListener(new JobEventHandler(){public void onJobFinished(){ client.writeRowEndPackage()}});

以上提供一個SQL執行框架,完全是異步的模式執行,並且以后會提供更多高質量的API,簡化分布式數據處理,比如內存結合文件的數據JOIN算法,分組算法,排序算法等等,

期待更多的牛人一起來完善。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM