分表:
分表分為水平分表和垂直分表。
水平分表原理:
分表策略通常是用戶ID取模,如果不是整數,可以首先將其進行hash獲取到整。
水平分表遇到的問題:
1. 跨表直接連接查詢無法進行
2. 我們需要統計數據的時候
3. 如果數據持續增長,達到現有分表的瓶頸,需要增加分表,此時會出現數據重新排列的情況
解決方案建議:
1. 第1,2點可以通過增加匯總的冗余表,雖然數據量很大,但是可以用於后台統計或者查詢時效性比較底的情況,而且我們可以提前算好某個時間點或者時間段的數據
2. 第3點解決建議:
1. 可以開始的時候,就分析大概的數據增長率,來大概確定未來某段時間內的數據總量,從而提前計算出未來某段時間內需要用到的分表的個數
2. 考慮表分區,在邏輯上面還是一個表名,實際物理存儲在不同的物理地址上
3. 分庫
垂直拆分原則:
1. 把大字段獨立存儲到一張表中
2. 把不常用的字段單獨拿出來存儲到一張表
3. 把經常在一起使用的字段可以拿出來單獨存儲到一張表
垂直拆分標准:
1.表的體積大於2G並且行數大於1千萬
2.表中包含有text,blob,varchar(1000)以上
3.數據有時效性的,可以單獨拿出來歸檔處理
/*表的體積計算*/
CREATE TABLE `test1` (
id bigint(20) not null auto_increment,
detail varchar(2000),
createtime datetime,
validity int default '0',
primary key (id)
);
1000萬 bigint 8字節 varchar 2000 字節 datetime 8字節 validity 4字節
(8+2000+8+4) * 10000000 = 20200000000 字節 == 18G
分表后體積:
CREATE TABLE `test1` (
id int not null auto_increment,
createtime timestamp,
validity tinyint default 0,
primary key (id)
);
(4+4+1) * 10000000 = 0.08G
分庫策略與分表策略的實現很相似,最簡單的都是可以通過取模的方式進行路由。
分庫也可以按照業務分庫,比如訂單表和庫存表在兩個庫,要注意處理好跨庫事務。
分表和分庫 同時實現。
分庫分表的策略相對於前邊兩種復雜一些,一種常見的路由策略如下:
1、中間變量 = user_id%(庫數量*每個庫的表數量);
2、庫序號 = 取整(中間變量/每個庫的表數量);
3、表序號 = 中間變量%每個庫的表數量;
例如:數據庫有256 個,每一個庫中有1024個數據表,用戶的user_id=262145,按照上述的路由策略,可得:
1、中間變量 = 262145%(256*1024)= 1;
2、庫序號 = 取整(1/1024)= 0;
3、表序號 = 1%1024 = 1;
這樣的話,對於user_id=262145,將被路由到第0個數據庫的第1個表中。
表分區:
就是將一個數據量比較大的表,用某種方法把數據從物理上分成若干個小表來存儲(類似水平分表),從邏輯來看還是一個大表。分表最大分1024,一般分100左右比較適合。
使用場景:
對於這種數據庫比較多,但是並發不是很多的情況下,可以采用表分區。
對於數據量比較大的,但是並發也比較高的情況下,可以采用分表和分區相結合。
/*range分區*/
create table test_range(
id int not null default 0
)engine=myisam default charset=utf8
partition by range(id)(
partition p1 values less than (3),
partition p2 values less than (5),
partition p3 values less than maxvalue
);
/*hash分區*/
create table test_hash(
id int not null default 0
)engine=innodb default charset=utf8
partition by hash(id) partitions 10;
/*線性hash分區*/
create table test_linear(
id int not null default 0
)engine=innodb default charset=utf8
partition by linear hash(id) partitions 10;
/* list分區*/
create table test_list(
id int not null
) engine=innodb default charset=utf8
partition by list(id)(
partition p0 values in (3,5),
partition p1 values in (2,6,7,9)
);
/* key 分區 */
CREATE TABLE test_key (
col1 INT NOT NULL
)
PARTITION BY linear KEY (col1)
PARTITIONS 10;
普通的hash分區 增加風區后,需要重新計算
線性hash分區(了解) 增加分區后,還是在原來的分區
線性hash 相對於 hash分區 沒有那么均勻
Key分區用的比較少,也是hash分區