爲何要分表和分區?html
平常開發中咱們常常會遇到大表的狀況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過於龐大,致使數據庫在查詢和插入的時候耗時太長,性能低下,若是涉及聯合查詢的狀況,性能會更加糟糕。分表和表分區的目的就是減小數據庫的負擔,提升數據庫的效率,一般點來說就是提升表的增刪改查效率。java
什麼是分表?mysql
分表是將一個大表按照必定的規則分解成多張具備獨立存儲空間的實體表,咱們能夠稱爲子表,每一個表都對應三個文件,MYD數據文件,.MYI索引文件,.frm表結構文件。這些子表能夠分佈在同一塊磁盤上,也能夠在不一樣的機器上。app讀寫的時候根據事先定義好的規則獲得對應的子表名,而後去操做它。sql
什麼是分區?數據庫
分區和分表類似,都是按照規則分解表。不一樣在於分表將大表分解爲若干個獨立的實體表,而分區是將數據分段劃分在多個位置存放,能夠是同一塊磁盤也能夠在不一樣的機器。分區後,表面上仍是一張表,但數據散列到多個位置了。app讀寫的時候操做的仍是大表名字,db自動去組織分區的數據。併發
mysql分表和分區有什麼聯繫呢?
1.都能提升mysql的性高,在高併發狀態下都有一個良好的表現。
2.分表和分區不矛盾,能夠相互配合的,對於那些大訪問量,而且表數據比較多的表,咱們能夠採起分表和分區結合的方式(若是merge這種分表方式,不能和分區配合的話,能夠用其餘的分表試),訪問量不大,可是表數據不少的表,咱們能夠採起分區的方式等。
3.分表技術是比較麻煩的,須要手動去建立子表,app服務端讀寫時候須要計算子表名。採用merge好一些,但也要建立子表和配置子表間的union關係。
4.表分區相對於分表,操做方便,不須要建立子表。app
分表的幾種方式:less
一、mysql集羣高併發
它並非分表,但起到了和分表相同的做用。集羣可分擔數據庫的操做次數,將任務分擔到多臺數據庫上。集羣能夠讀寫分離,減小讀寫壓力。從而提高數據庫性能。性能
二、自定義規則分表
大表能夠按照業務的規則來分解爲多個子表。一般爲如下幾種類型,也可本身定義規則。
1
2
3
4
5
|
Range(範圍)–這種模式容許將數據劃分不一樣範圍。例如能夠將一個表經過年份劃分紅若干個分區。
Hash(哈希)–這中模式容許經過對錶的一個或多個列的Hash
Key
進行計算,最後經過這個Hash碼不一樣數值對應的數據區域進行分區。例如能夠創建一個對錶主鍵進行分區的表。
Key
(鍵值)-上面Hash模式的一種延伸,這裏的Hash
Key
是MySQL系統產生的。
List(預約義列表)–這種模式容許系統經過預約義的列表的值來對數據進行分割。
Composite(複合模式) –以上模式的組合使用
|
分表規則與分區規則同樣,在分區模塊詳細介紹。
下面以Range簡單介紹下如何分表(按照年份表)。
假設表結構有4個字段:自增id,姓名,存款金額,存款日期
把存款日期做爲規則分表,分別建立幾個表
2011年:account_2011
2012年:account_2012
……
2015年:account_2015
app在讀寫的時候根據日期來查找對應的表名,須要手動來斷定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
var getTableName =
function
() {
var data = {
name
:
'tom'
,
money: 2800.00,
date
:
'201410013059'
};
var tablename =
'account_'
;
var
year
= parseInt(data.
date
.
substring
(0, 4));
if (
year
< 2012) {
tablename += 2011; // account_2011
}
else
if (
year
< 2013) {
tablename += 2012; // account_2012
}
else
if (
year
< 2014) {
tablename += 2013; // account_2013
}
else
if (
year
< 2015) {
tablename += 2014; // account_2014
}
else
{
tablename += 2015; // account_2015
}
return
tablename;
}
|
三、利用merge存儲引擎來實現分表
merge分表,分爲主表和子表,主表相似於一個殼子,邏輯上封裝了子表,實際上數據都是存儲在子表中的。
咱們能夠經過主表插入和查詢數據,若是清楚分表規律,也能夠直接操做子表。
子表2011年
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
CREATE
TABLE
`account_2011` (
`id`
int
(11)
NOT
NULL
AUTO_INCREMENT ,
`
name
`
varchar
(50)
CHARACTER
SET
utf8
COLLATE
utf8_general_ci
NULL
DEFAULT
NULL
,
`money`
float
NOT
NULL
,
`tradeDate` datetime
NOT
NULL
PRIMARY
KEY
(`id`)
)
ENGINE=MyISAM
DEFAULT
CHARACTER
SET
=utf8
COLLATE
=utf8_general_ci
AUTO_INCREMENT=2
CHECKSUM=0
ROW_FORMAT=
DYNAMIC
DELAY_KEY_WRITE=0
;
|
子表2012年
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
CREATE
TABLE
`account_2012` (
`id`
int
(11)
NOT
NULL
AUTO_INCREMENT ,
`
name
`
varchar
(50)
CHARACTER
SET
utf8
COLLATE
utf8_general_ci
NULL
DEFAULT
NULL
,
`money`
float
NOT
NULL
,
`tradeDate` datetime
NOT
NULL
PRIMARY
KEY
(`id`)
)
ENGINE=MyISAM
DEFAULT
CHARACTER
SET
=utf8
COLLATE
=utf8_general_ci
AUTO_INCREMENT=2
CHECKSUM=0
ROW_FORMAT=
DYNAMIC
DELAY_KEY_WRITE=0
;
|
主表,全部年
1
2
3
4
5
6
7
8
9
10
11
12
13
|
CREATE
TABLE
`account_all` (
`id`
int
(11)
NOT
NULL
AUTO_INCREMENT ,
`
name
`
varchar
(50)
CHARACTER
SET
utf8
COLLATE
utf8_general_ci
NULL
DEFAULT
NULL
,
`money`
float
NOT
NULL
,
`tradeDate` datetime
NOT
NULL
PRIMARY
KEY
(`id`)
)
ENGINE=MRG_MYISAM
DEFAULT
CHARACTER
SET
=utf8
COLLATE
=utf8_general_ci
UNION
=(`account_2011`,`account_2012`)
INSERT_METHOD=
LAST
ROW_FORMAT=
DYNAMIC
;
|
建立主表的時候有個INSERT_METHOD,指明插入方式,取值能夠是:0 不容許插入;FIRST 插入到UNION中的第一個表; LAST 插入到UNION中的最後一個表。
經過主表查詢的時候,至關於將全部子表合在一塊兒查詢。這樣並不能體現分表的優點,建議仍是查詢子表。
分區的幾種方式
Range:
1
2
3
4
5
6
7
8
9
10
|
create
table
range(
id
int
(11),
money
int
(11) unsigned
not
null
,
date
datetime
)partition
by
range(
year
(
date
))(
partition p2007
values
less than (2008),
partition p2008
values
less than (2009),
partition p2009
values
less than (2010)
partition p2010
values
less than maxvalue
);
|
List:
1
2
3
4
5
6
7
|
create
table
list(
a
int
(11),
b
int
(11)
)(partition
by
list (b)
partition p0
values
in
(1,3,5,7,9),
partition p1
values
in
(2,4,6,8,0)
);
|
Hash:
1
2
3
4
5
|
create
table
hash(
a
int
(11),
b datetime
)partition
by
hash (
YEAR
(b)
partitions 4;
|
Key:
1
2
3
4
5
|
create
table
t_key(
a
int
(11),
b datetime)
partition
by
key
(b)
partitions 4;
|
分區管理
新增分區
1
2
|
ALTER TABLE sale_data
ADD PARTITION (PARTITION p201010 VALUES LESS THAN (
201011
));
|
刪除分區
--當刪除了一個分區,也同時刪除了該分區中全部的數據。
ALTER TABLE sale_data DROP PARTITION p201010;
分區的合併
下面的SQL,將p201001 - p201009 合併爲3個分區p2010Q1 - p2010Q3
1
2
3
4
5
6
7
8
9
|
ALTER TABLE sale_data
REORGANIZE PARTITION p201001,p201002,p201003,
p201004,p201005,p201006,
p201007,p201008,p201009 INTO
(
PARTITION p2010Q1 VALUES LESS THAN (
201004
),
PARTITION p2010Q2 VALUES LESS THAN (
201007
),
PARTITION p2010Q3 VALUES LESS THAN (
201010
)
);
|