mysql分庫分表一般有如下場景
成都創(chuàng)新互聯(lián)主營瀘縣網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶App定制開發(fā),瀘縣h5微信小程序搭建,瀘縣網(wǎng)站營銷推廣歡迎瀘縣等地區(qū)企業(yè)咨詢
其中1,2相對較容易實現(xiàn),本文重點講講水平拆表和水平拆庫,以及基于mybatis插件方式實現(xiàn)水平拆分方案落地。
在 《聊一聊擴展字段設(shè)計》 一文中有講解到基于KV水平存儲擴展字段方案,這就是非常典型的可以水平分表的場景。主表和kv表是一對N關(guān)系,隨著主表數(shù)據(jù)量增長,KV表最大N倍線性增長。
這里我們以分KV表水平拆分為場景
對于kv擴展字段查詢,只會根據(jù)id + key 或者 id 為條件的方式查詢,所以這里我們可以按照id 分片即可
分512張表(實際場景具體分多少表還得根據(jù)字段增加的頻次而定)
分表后表名為kv_000 ~ kv_511
id % 512 = 1 .... 分到 kv_001,
id % 512 = 2 .... 分到 kv_002
依次類推!
水平分表相對比較容易,后面會講到基于mybatis插件實現(xiàn)方案
場景:以下我們基于博客文章表分庫場景來分析
目標:
表結(jié)構(gòu)如下(節(jié)選部分字段):
按照user_id sharding
假如分1024個庫,按照user_id % 1024 hash
user_id % 1024 = 1 分到db_001庫
user_id % 1024 = 2 分到db_002庫
依次類推
目前是2個節(jié)點,假如后期達到瓶頸,我們可以增加至4個節(jié)點
最多可以增加只1024個節(jié)點,性能線性增長
對于水平分表/分庫后,非shardingKey查詢首先得考慮到
基于mybatis分庫分表,一般常用的一種是基于spring AOP方式, 另外一種基于mybatis插件。其實兩種方式思路差不多。
為了比較直觀解決這個問題,我分別在Executor 和StatementHandler階段2個攔截器
實現(xiàn)動態(tài)數(shù)據(jù)源獲取接口
測試結(jié)果如下
由此可知,我們需要在Executor階段 切換數(shù)據(jù)源
對于分庫:
原始sql:
目標sql:
其中定義了三個注解
@useMaster 是否強制讀主
@shardingBy 分片標識
@DB 定義邏輯表名 庫名以及分片策略
1)編寫entity
Insert
select
以上順利實現(xiàn)mysql分庫,同樣的道理實現(xiàn)同時分庫分表也很容易實現(xiàn)。
此插件具體實現(xiàn)方案已開源:
目錄如下:
mysql分庫分表,首先得找到瓶頸在哪里(IO or CPU),是分庫還是分表,分多少?不能為了分庫分表而拆分。
原則上是盡量先垂直拆分 后 水平拆分。
以上基于mybatis插件分庫分表是一種實現(xiàn)思路,還有很多不完善的地方,
例如:
分區(qū)
分區(qū)就是把一個數(shù)據(jù)表的文件和索引分散存儲在不同的物理文件中。
mysql支持的分區(qū)類型包括Range、List、Hash、Key,其中Range比較常用:
RANGE分區(qū):基于屬于一個給定連續(xù)區(qū)間的列值,把多行分配給分區(qū)。
LIST分區(qū):類似于按RANGE分區(qū),區(qū)別在于LIST分區(qū)是基于列值匹配一個離散值集合中的某個值來進行選擇。
HASH分區(qū):基于用戶定義的表達式的返回值來進行選擇的分區(qū),該表達式使用將要插入到表中的這些行的列值進行計算。這個函數(shù)可以包含MySQL 中有效的、產(chǎn)生非負整數(shù)值的任何表達式。
KEY分區(qū):類似于按HASH分區(qū),區(qū)別在于KEY分區(qū)只支持計算一列或多列,且MySQL服務(wù)器提供其自身的哈希函數(shù)。必須有一列或多列包含整數(shù)值。
分表
分表和分區(qū)類似,區(qū)別是,分區(qū)是把一個邏輯表文件分成幾個物理文件后進行存儲,而分表則是把原先的一個表分成幾個表。進行分表查詢時可以通過union或者視圖。
分表又分垂直分割和水平分割,其中水平分分割最為常用。水平分割通常是指切分到另外一個數(shù)據(jù)庫或表中 。
你這樣的情況可以使用UNION
SELECT * FROM user01 WHERE pid=張三的ID UNION
SELECT * FROM user02 WHERE pid=張三的ID UNION
SELECT * FROM user03 WHERE pid=張三的ID
【張三的ID】先用語句查詢出來:
SELECT id FROM user01 WHERE name='張三' UNION
SELECT id FROM user02 WHERE name='張三' UNION
SELECT id FROM user03 WHERE name='張三'
其實一般建議不這樣分表,數(shù)據(jù)太大可以考慮使用專業(yè)點的DBMS,程序像使用當個邏輯表,表的存儲由系統(tǒng)優(yōu)化,有可能分布在一系列磁盤陣列上,甚至可能是分布在多個服務(wù)器上。
mysql數(shù)據(jù)庫對1億條數(shù)據(jù)的分表方法設(shè)計:
目前針對海量數(shù)據(jù)的優(yōu)化有兩種方法:
(1)垂直分割
優(yōu)勢:降低高并發(fā)情況下,對于表的鎖定。
不足:對于單表來說,隨著數(shù)據(jù)庫的記錄增多,讀寫壓力將進一步增大。
(2)水平分割
如果單表的IO壓力大,可以考慮用水平分割,其原理就是通過hash算法,將一張表分為N多頁,并通過一個新的表(總表),記錄著每個頁的的位置。
假如一個門戶網(wǎng)站,它的數(shù)據(jù)庫表已經(jīng)達到了1億條記錄,那么此時如果通過select去查詢,必定會效率低下(不做索引的前提下)。為了降低單表的讀寫IO壓力,通過水平分割,將這個表分成10個頁,同時生成一個總表,記錄各個頁的信息,那么假如我查詢一條id=100的記錄,它不再需要全表掃描,而是通過總表找到該記錄在哪個對應(yīng)的頁上,然后再去相應(yīng)的頁做檢索,這樣就降低了IO壓力。