1. 程式人生 > >分表需要解決的問題 & 基於MyBatis 的輕量分表落地方案

分表需要解決的問題 & 基於MyBatis 的輕量分表落地方案

語法 分開 lec 字段拆分 sql解析 準備 red 強一致性 運維管理

分表:垂直拆分、水平拆分
垂直拆分:根據業務將一個表拆分為多個表。
如:將經常和不常訪問的字段拆分至不同的表中。由於與業務關系密切,目前的分庫分表產品均使用水平拆分方式。
水平拆分:根據分片算法將一個表拆分為多個表。
如:按照ID的最後一位以3取余,尾數是1的放入第1個庫(表),尾數是2的放入第2個庫(表)等。

解決的問題:單純的分表可以解決數據量過大導致檢索變慢的問題。

分表無法解決過多並發請求訪問同一個庫,導致數據庫響應變慢的問題。所以通常水平拆分都至少要采用分庫的方式,用於一並解決大數據量和高並發的問題。這也是部分開源的分片數據庫中間件只支持分庫的原因。

分表不可替代的場景:最常見的分表需求是事務問題。

同在一個庫則不需考慮分布式事務,善於使用同庫不同表可有效避免分布式事務帶來的麻煩。目前強一致性的分布式事務由於性能問題,導致使用起來並不一定比不分庫分表快。目前采用最終一致性的柔性事務居多。分表的另一個存在的理由是,過多的數據庫實例不利於運維管理。

綜上所述,最佳實踐是合理地配合使用分庫+分表。

https://blog.csdn.net/u4110122855/article/details/50670503


MyBatis輕量分表落地方案:


分表需要解決的問題:(基於MyBatis來說明)
1. SQL解析
2. SQL改寫
3. SQL執行
4. 結果合並

1. SQL解析
SQL語法樹解析,為SQL改寫做準備


2. SQL改寫
按分片規則將 SQL 進行改寫。
做為一個中間件產品,需要屏蔽分表的細節,到底分了多少個表,對使用者來說應該是透明的。所以使用者寫出的 SQL 中的表是一個虛擬的表。
例如:有表 user_0, user_1,分片規則是 id%2
使用者寫出的insert 語句:insert into user(id, name) values(1, ‘張三‘)
那麽中間件需要將 SQL 改寫為:insert into user_1(id, name) values(1, ‘張三‘)

改寫出的 SQL 可能不止一條,例如:select * from user where id in (1, 2)
改寫後的 SQL 應該是:select * from user_0 where id in (1, 2)
select * from user_1 where id in (1, 2)

3. SQL執行
MyBatis執行 SQL 時,最後是通過 PreparedStatementHandler#instantiateStatement(Connection) 來獲取 Statement 的。它會從 BoundSql裏面取需要執行的 sql 語句。
通過跟代碼發現, BoundSql 是從 MappedStatement 中取出來的。
所以,我們 SQL 執行時,可以通過 MyBatis 的攔截器攔截 MappedStatement (即:Executor的query、update方法),然後改寫 MappedStatement#getBoundSql()就可以了。

4. 結果合並
由於 SQL 改寫後,我們需要執行的 SQL 不只一條,所以,當 SQL 有多條時,我們就需要將 SQL 執行的結果集合並出最終的結果。


基於MyBatis 的輕量分表實現:https://gitee.com/kkk001/mybatis-shard

分表需要解決的問題 & 基於MyBatis 的輕量分表落地方案