mysql分區功能詳解及實例代碼分析

下面小編就為大家帶來一篇mysql分區功能詳解,以及實例分析。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一,什么是數據庫分區

前段時間寫過一篇關于mysql分表的 的文章,下面來說一下什么是數據庫分區,以mysql為例。mysql數據庫中的數據是以文件的形勢存在磁盤上的,默認放在/mysql/data下面 (可以通過my.cnf中的datadir來查看),一張表主要對應著三個文件,一個是frm存放表結構的,一個是myd存放表數據的,一個是myi存表 索引的。如果一張表的數據量太大的話,那么myd,myi就會變的很大,查找數據就會變的很慢,這個時候我們可以利用mysql的分區功能,在物理上將這 一張表對應的三個文件,分割成許多個小塊,這樣呢,我們查找一條數據時,就不用全部查找了,只要知道這條數據在哪一塊,然后在那一塊找就行了。如果表的數 據太大,可能一個磁盤放不下,這個時候,我們可以把數據分配到不同的磁盤里面去。

分區的二種方式

1,橫向分區

什么是橫向分區呢?就是橫著來分區了,舉例來說明一下,假如有100W條數據,分成十份,前10W條數據放到第一個分區,第二個10W條數據放到第二個分區,依此類推。也就是把表分成了十分,根用merge來分表,有點像哦。取出一條數據的時候,這條數據包含了表結構中的所有字段,也就是說橫向分區,并沒有改變表的結構。

2,縱向分區

什么是縱向分區呢?就是豎來分區了,舉例來說明,在設計用戶表的時候,開始的時候沒有考慮好,而把個人的所有信息都放到了一張表里面去,這樣這個表里面就會有比較大的字段,如個人mysql,而這些簡介呢,也許不會有好多人去看,所以等到有人要看的時候,在去查找,分表的時候,可以把這樣的大字段,分開來。

感覺數據庫的分區好像是切蘋果,到底是橫著切呢,還是豎著切,根據個人喜好了,mysql提供的分區屬于第一種,橫向分區,并且細分成很多種方式。下面將舉例說明一下。

二,mysql的分區

我覺著吧,mysql的分區只有一種方式,只不過運用不同的算法,規則將數據分配到不同的區塊中而已。

1,mysql5.1及以上支持分區功能

mysql安裝的時候,我們就可以查看一下

[root@BlackGhost?mysql-5.1.50]#?./configure?--help?|grep?-A?3?Partition?  ===?Partition?Support?===?  Plugin?Name:???partition?  Description:???MySQL?Partitioning?Support?  Supports?build:??static?  Configurations:??max,?max-no-ndb

查看一下,如果發現有上面這個東西,說明他是支持分區的,默認是打開的。如果你已經安裝過了mysql的話

mysql>?show?variables?like?"%part%";?  +-------------------+-------+?  |?Variable_name???|?Value?|?  +-------------------+-------+?  |?have_partitioning?|?YES??|?  +-------------------+-------+?  1?row?in?set?(0.00?sec)

查看一下mysql,如果支持的話,會有上面的提示的。

2,mysql分區

按照RANGE分區的表是通過如下一種方式進行分區的,每個分區包含那些分區表達式的值位于一個給定的連續區間內的行

//創建range分區表?  mysql>?CREATE?TABLE?IF?NOT?EXISTS?`user`?(?  ?->??`id`?int(11)?NOT?NULL?AUTO_INCREMENT?COMMENT?'用戶ID',?  ?->??`name`?varchar(50)?NOT?NULL?DEFAULT?''?COMMENT?'名稱',?  ?->??`sex`?int(1)?NOT?NULL?DEFAULT?'0'?COMMENT?'0為男,1為女',?  ?->??PRIMARY?KEY?(`id`)?  ?->?)?ENGINE=MyISAM?DEFAULT?CHARSET=utf8?AUTO_INCREMENT=1?  ?->?PARTITION?BY?RANGE?(id)?(?  ?->???PARTITION?p0?VALUES?LESS?THAN?(3),?  ?->???PARTITION?p1?VALUES?LESS?THAN?(6),?  ?->???PARTITION?p2?VALUES?LESS?THAN?(9),?  ?->???PARTITION?p3?VALUES?LESS?THAN?(12),?  ?->???PARTITION?p4?VALUES?LESS?THAN?MAXVALUE?  ?->?);?  Query?OK,?0?rows?affected?(0.13?sec)?  ?  //插入一些數據?  mysql>?INSERT?INTO?`test`.`user`?(`name`?,`sex`)VALUES?('tank',?'0')?  ?->?,('zhang',1),('ying',1),('張',1),('映',0),('test1',1),('tank2',1)?  ?->?,('tank1',1),('test2',1),('test3',1),('test4',1),('test5',1),('tank3',1)?  ?->?,('tank4',1),('tank5',1),('tank6',1),('tank7',1),('tank8',1),('tank9',1)?  ?->?,('tank10',1),('tank11',1),('tank12',1),('tank13',1),('tank21',1),('tank42',1);?  Query?OK,?25?rows?affected?(0.05?sec)?  Records:?25?Duplicates:?0?Warnings:?0?  ?  //到存放數據庫表文件的地方看一下,my.cnf里面有配置,datadir后面就是?  [root@BlackGhost?test]#?ls?|grep?user?|xargs?du?-sh?  4.0K??user#P#p0.MYD?  4.0K??user#P#p0.MYI?  4.0K??user#P#p1.MYD?  4.0K??user#P#p1.MYI?  4.0K??user#P#p2.MYD?  4.0K??user#P#p2.MYI?  4.0K??user#P#p3.MYD?  4.0K??user#P#p3.MYI?  4.0K??user#P#p4.MYD?  4.0K??user#P#p4.MYI?  12K??user.frm?  4.0K??user.par?  ?  //取出數據?  mysql>?select?count(id)?as?count?from?user;?  +-------+?  |?count?|?  +-------+?  |??25?|?  +-------+?  1?row?in?set?(0.00?sec)?  ?  //刪除第四個分區?  mysql>?alter?table?user?drop?partition?p4;?  Query?OK,?0?rows?affected?(0.11?sec)?  Records:?0?Duplicates:?0?Warnings:?0?  ?  /**存放在分區里面的數據丟失了,第四個分區里面有14條數據,剩下的3個分區?  只有11條數據,但是統計出來的文件大小都是4.0K,從這兒我們可以看出分區的?  最小區塊是4K?  */?  mysql>?select?count(id)?as?count?from?user;?  +-------+?  |?count?|?  +-------+?  |??11?|?  +-------+?  1?row?in?set?(0.00?sec)?  ?  //第四個區塊已刪除?  [root@BlackGhost?test]#?ls?|grep?user?|xargs?du?-sh?  4.0K??user#P#p0.MYD?  4.0K??user#P#p0.MYI?  4.0K??user#P#p1.MYD?  4.0K??user#P#p1.MYI?  4.0K??user#P#p2.MYD?  4.0K??user#P#p2.MYI?  4.0K??user#P#p3.MYD?  4.0K??user#P#p3.MYI?  12K??user.frm?  4.0K??user.par?  ?  /*可以對現有表進行分區,并且會按規則自動的將表中的數據分配相應的分區?  中,這樣就比較好了,可以省去很多事情,看下面的操作*/?  mysql>?alter?table?aa?partition?by?RANGE(id)?  ?->?(PARTITION?p1?VALUES?less?than?(1),?  ?->?PARTITION?p2?VALUES?less?than?(5),?  ?->?PARTITION?p3?VALUES?less?than?MAXVALUE);?  Query?OK,?15?rows?affected?(0.21?sec)??//對15數據進行分區?  Records:?15?Duplicates:?0?Warnings:?0?  ?  //總共有15條?  mysql>?select?count(*)?from?aa;?  +----------+?  |?count(*)?|?  +----------+?  |????15?|?  +----------+?  1?row?in?set?(0.00?sec)?  ?  //刪除一個分區?  mysql>?alter?table?aa?drop?partition?p2;?  Query?OK,?0?rows?affected?(0.30?sec)?  Records:?0?Duplicates:?0?Warnings:?0?  ?  //只有11條了,說明對現有的表分區成功了?  mysql>?select?count(*)?from?aa;?  +----------+?  |?count(*)?|?  +----------+?  |????11?|?  +----------+?  1?row?in?set?(0.00?sec)

3,mysql分區

LIST分區中每個分區的定義和選擇是基于某列的值從屬于一個值列表集中的一個值,而RANGE分 區是從屬于一個連續區間值的集合。

//這種方式失敗?  mysql>?CREATE?TABLE?IF?NOT?EXISTS?`list_part`?(?  ?->??`id`?int(11)?NOT?NULL?AUTO_INCREMENT?COMMENT?'用戶ID',?  ?->??`province_id`?int(2)?NOT?NULL?DEFAULT?0?COMMENT?'省',?  ?->??`name`?varchar(50)?NOT?NULL?DEFAULT?''?COMMENT?'名稱',?  ?->??`sex`?int(1)?NOT?NULL?DEFAULT?'0'?COMMENT?'0為男,1為女',?  ?->??PRIMARY?KEY?(`id`)?  ?->?)?ENGINE=INNODB?DEFAULT?CHARSET=utf8?AUTO_INCREMENT=1?  ?->?PARTITION?BY?LIST?(province_id)?(?  ?->???PARTITION?p0?VALUES?IN?(1,2,3,4,5,6,7,8),?  ?->???PARTITION?p1?VALUES?IN?(9,10,11,12,16,21),?  ?->???PARTITION?p2?VALUES?IN?(13,14,15,19),?  ?->???PARTITION?p3?VALUES?IN?(17,18,20,22,23,24)?  ?->?);?  ERROR?1503?(HY000):?A?PRIMARY?KEY?must?include?all?columns?in?the?table's?partitioning?function?  ?  //這種方式成功?  mysql>?CREATE?TABLE?IF?NOT?EXISTS?`list_part`?(?  ?->??`id`?int(11)?NOT?NULL?COMMENT?'用戶ID',?  ?->??`province_id`?int(2)?NOT?NULL?DEFAULT?0?COMMENT?'省',?  ?->??`name`?varchar(50)?NOT?NULL?DEFAULT?''?COMMENT?'名稱',?  ?->??`sex`?int(1)?NOT?NULL?DEFAULT?'0'?COMMENT?'0為男,1為女'?  ?->?)?ENGINE=INNODB?DEFAULT?CHARSET=utf8?  ?->?PARTITION?BY?LIST?(province_id)?(?  ?->???PARTITION?p0?VALUES?IN?(1,2,3,4,5,6,7,8),?  ?->???PARTITION?p1?VALUES?IN?(9,10,11,12,16,21),?  ?->???PARTITION?p2?VALUES?IN?(13,14,15,19),?  ?->???PARTITION?p3?VALUES?IN?(17,18,20,22,23,24)?  ?->?);?  Query?OK,?0?rows?affected?(0.33?sec)

上面的這個創建list分區時,如果有主銉的話,分區時主鍵必須在其中,不然就會報錯。如果我不用主鍵,分區就創建成功了,一般情況下,一個張表肯定會有一個主鍵,這算是一個分區的局限性吧。

如果對數據進行測試,請參考range分區的測試來操作

4,mysql分區

HASH分區主要用來確保數據在預先確定數目的分區中平均分布,你所要做的只是基于將要被哈希的列值指定一個列值或表達式,以 及指定被分區的表將要被分割成的分區數量。

mysql>?CREATE?TABLE?IF?NOT?EXISTS?`hash_part`?(?  ?->??`id`?int(11)?NOT?NULL?AUTO_INCREMENT?COMMENT?'評論ID',?  ?->??`comment`?varchar(1000)?NOT?NULL?DEFAULT?''?COMMENT?'評論',?  ?->??`ip`?varchar(25)?NOT?NULL?DEFAULT?''?COMMENT?'來源IP',?  ?->??PRIMARY?KEY?(`id`)?  ?->?)?ENGINE=INNODB?DEFAULT?CHARSET=utf8?AUTO_INCREMENT=1?  ?->?PARTITION?BY?HASH(id)?  ?->?PARTITIONS?3;?  Query?OK,?0?rows?affected?(0.06?sec)

測試請參考range分區的操作

5,key分區

按照KEY進行分區類似于按照HASH分區,除了HASH分區使用的用 戶定義的表達式,而KEY分區的 哈希mysql是由MySQL 服務器提供。

mysql>?CREATE?TABLE?IF?NOT?EXISTS?`key_part`?(?  ?->??`news_id`?int(11)?NOT?NULL?COMMENT?'新聞ID',?  ?->??`content`?varchar(1000)?NOT?NULL?DEFAULT?''?COMMENT?'新聞內容',?  ?->??`u_id`?varchar(25)?NOT?NULL?DEFAULT?''?COMMENT?'來源IP',?  ?->??`create_time`?DATE?NOT?NULL?DEFAULT?'0000-00-00?00:00:00'?COMMENT?'時間'?  ?->?)?ENGINE=INNODB?DEFAULT?CHARSET=utf8?  ?->?PARTITION?BY?LINEAR?HASH(YEAR(create_time))?  ?->?PARTITIONS?3;?  Query?OK,?0?rows?affected?(0.07?sec)

測試請參考range分區的操作

6,子分區

子分區是分區表中每個分區的再次分割,子分區既可以使用HASH希分區,也可以使用KEY分區。這 也被稱為復合分區(composite partitioning)。

1,如果一個分區中創建了子分區,其他分區也要有子分區

2,如果創建了了分區,每個分區中的子分區數必有相同

3,同一分區內的子分區,名字不相同,不同分區內的子分區名子可以相同(5.1.50不適用)

mysql>?CREATE?TABLE?IF?NOT?EXISTS?`sub_part`?(?  ?->??`news_id`?int(11)?NOT?NULL?COMMENT?'新聞ID',?  ?->??`content`?varchar(1000)?NOT?NULL?DEFAULT?''?COMMENT?'新聞內容',?  ?->??`u_id`?int(11)?NOT?NULL?DEFAULT?0s?COMMENT?'來源IP',?  ?->??`create_time`?DATE?NOT?NULL?DEFAULT?'0000-00-00?00:00:00'?COMMENT?'時間'?  ?->?)?ENGINE=INNODB?DEFAULT?CHARSET=utf8?  ?->?PARTITION?BY?RANGE(YEAR(create_time))?  ?->?SUBPARTITION?BY?HASH(TO_DAYS(create_time))(?  ?->?PARTITION?p0?VALUES?LESS?THAN?(1990)(SUBPARTITION?s0,SUBPARTITION?s1,SUBPARTITION?s2),?  ?->?PARTITION?p1?VALUES?LESS?THAN?(2000)(SUBPARTITION?s3,SUBPARTITION?s4,SUBPARTITION?good),?  ?->?PARTITION?p2?VALUES?LESS?THAN?MAXVALUE(SUBPARTITION?tank0,SUBPARTITION?tank1,SUBPARTITION?tank3)?  ?->?);?  Query?OK,?0?rows?affected?(0.07?sec)

官方網站說不同分區內的子分區可以有相同的名字,但是mysql5.1.50卻不行會提示以下錯誤

ERROR 1517 (HY000): Duplicate partition name s1

三,分區管理

1,刪除分區

1.mysql>?alter?table?user?drop?partition?p4;

2,mysql分區

//range添加新分區?  mysql>?alter?table?user?add?partition(partition?p4?values?less?than?MAXVALUE);?  Query?OK,?0?rows?affected?(0.06?sec)?  Records:?0?Duplicates:?0?Warnings:?0?  ?  //list添加新分區?  mysql>?alter?table?list_part?add?partition(partition?p4?values?in?(25,26,28));?  Query?OK,?0?rows?affected?(0.01?sec)?  Records:?0?Duplicates:?0?Warnings:?0?  ?  //hash重新分區?  mysql>?alter?table?hash_part?add?partition?partitions?4;?  Query?OK,?0?rows?affected?(0.12?sec)?  Records:?0?Duplicates:?0?Warnings:?0?  ?  //key重新分區?  mysql>?alter?table?key_part?add?partition?partitions?4;?  Query?OK,?1?row?affected?(0.06?sec)??//有數據也會被重新分配?  Records:?1?Duplicates:?0?Warnings:?0?  ?  //子分區添加新分區,雖然我沒有指定子分區,但是系統會給子分區命名的?  mysql>?alter?table?sub1_part?add?partition(partition?p3?values?less?than?MAXVALUE);?  Query?OK,?0?rows?affected?(0.02?sec)?  Records:?0?Duplicates:?0?Warnings:?0?  ?  mysql>?show?create?table?sub1_partG;?  ***************************?1.?row?***************************?  ?Table:?sub1_part?  Create?Table:?CREATE?TABLE?`sub1_part`?(?  ?`news_id`?int(11)?NOT?NULL?COMMENT?'新聞ID',?  ?`content`?varchar(1000)?NOT?NULL?DEFAULT?''?COMMENT?'新聞內容',?  ?`u_id`?varchar(25)?NOT?NULL?DEFAULT?''?COMMENT?'來源IP',?  ?`create_time`?date?NOT?NULL?DEFAULT?'0000-00-00'?COMMENT?'時間'?  )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8?  !50100?PARTITION?BY?RANGE?(YEAR(create_time))?  SUBPARTITION?BY?HASH?(TO_DAYS(create_time))?  (PARTITION?p0?VALUES?LESS?THAN?(1990)?  ?(SUBPARTITION?s0?ENGINE?=?InnoDB,?  ?SUBPARTITION?s1?ENGINE?=?InnoDB,?  ?SUBPARTITION?s2?ENGINE?=?InnoDB),?  ?PARTITION?p1?VALUES?LESS?THAN?(2000)?  ?(SUBPARTITION?s3?ENGINE?=?InnoDB,?  ?SUBPARTITION?s4?ENGINE?=?InnoDB,?  ?SUBPARTITION?good?ENGINE?=?InnoDB),?  ?PARTITION?p2?VALUES?LESS?THAN?(3000)?  ?(SUBPARTITION?tank0?ENGINE?=?InnoDB,?  ?SUBPARTITION?tank1?ENGINE?=?InnoDB,?  ?SUBPARTITION?tank3?ENGINE?=?InnoDB),?  ?PARTITION?p3?VALUES?LESS?THAN?MAXVALUE?  ?(SUBPARTITION?p3sp0?ENGINE?=?InnoDB,??//子分區的名子是自動生成的?  ?SUBPARTITION?p3sp1?ENGINE?=?InnoDB,?  ?SUBPARTITION?p3sp2?ENGINE?=?InnoDB))?  1?row?in?set?(0.00?sec)

3,重新分區

//range重新分區?  mysql>?ALTER?TABLE?user?REORGANIZE?PARTITION?p0,p1,p2,p3,p4?INTO?(PARTITION?p0?VALUES?LESS?THAN?MAXVALUE);?  Query?OK,?11?rows?affected?(0.08?sec)?  Records:?11?Duplicates:?0?Warnings:?0?  ?  //list重新分區?  mysql>?ALTER?TABLE?list_part?REORGANIZE?PARTITION?p0,p1,p2,p3,p4?INTO?(PARTITION?p0?VALUES?in?(1,2,3,4,5));?  Query?OK,?0?rows?affected?(0.28?sec)?  Records:?0?Duplicates:?0?Warnings:?0?  ?  //hash和key分區不能用REORGANIZE,官方網站說的很清楚?  mysql>?ALTER?TABLE?key_part?REORGANIZE?PARTITION?COALESCE?PARTITION?9;?  ERROR?1064?(42000):?You?have?an?error?in?your?SQL?syntax;?  check?the?manual?that?corresponds?to?your?MySQL?server?version?for?the?right?syntax?to?use?near?'PARTITION?9'?at?line?1

四,分區優點

1,分區可以分在多個磁盤,存儲更大一點

2,根據查找條件,也就是where后面的條件,查找只查找相應的分區不用全部查找了

3,進行大數據mysql時可以進行并行處理。

4,跨多個磁盤來分散數據mysql,來獲得更大的查詢吞吐量

? 版權聲明
THE END
喜歡就支持一下吧
點贊14 分享