MySQL的分區、分表、集羣

1.分區

複製代碼

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

複製代碼

分區的二種方式

a,橫向分區

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

b,縱向分區

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

mysql提供的分區屬於第一種,橫向分區,並且細分成很多種方式:

1.1 MySQL5.1及以上支持分區功能

複製代碼

查看是否支持分區
mysql> show variables like "%part%";  
+-------------------+-------+  
| Variable_name     | Value |  
+-------------------+-------+  
| have_partitioning | YES   |  
+-------------------+-------+  
1 row in set (0.00 sec) 

複製代碼

 

1.2 range 分區

      這種模式允許將數據劃分不同範圍。例如可以將一個表通過年份劃分成若干個分區

複製代碼

 create table t_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  #MAXVALUE 表示最大的可能的整數值
  );

RANGE分區在如下場合特別有用:
1)、當需要刪除一個分區上的“舊的”數據時,只刪除分區即可。如果你使用上面最近的那個例子給出的分區方案,你只需簡單地使用”ALTER TABLE employees DROP PARTITION p0;”
  來刪除所有在1991年前就已經停止工作的僱員相對應的所有行。對於有大量行的表,這比運行一個如”DELETE FROM employees WHERE YEAR (separated) <= 1990;”
  這樣的一個DELETE查詢要有效得多。 
2)、想要使用一個包含有日期或時間值,或包含有從一些其他級數開始增長的值的列。
3)、經常運行直接依賴於用於分割表的列的查詢。
  例如,當執行一個如”SELECT COUNT(*) FROM employees WHERE YEAR(separated) = 2000 GROUP BY store_id;”這樣的查詢時,
  MySQL可以很迅速地確定只有分區p2需要掃描,這是因爲餘下的分區不可能包含有符合該WHERE子句的任何記錄

複製代碼

 

1.3 list分區

      這種模式允許系統通過預定義的列表的值來對數據進行分割。

  

複製代碼

create table t_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) 
);
LIST分區沒有類似如“VALUES LESS THAN MAXVALUE”這樣的包含其他值在內的定義。將要匹配的任何值都必須在值列表中找到。

複製代碼

 

1.4 hash分區

   這中模式允許通過對錶的一個或多個列的Hash Key進行計算,最後通過這個Hash碼不同數值對應的數據區域進行分區。例如可以建立一個對錶主鍵進行分區的表。

複製代碼

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4;

複製代碼

 

1.5 key分區

      上面Hash模式的一種延伸,這裏的Hash Key是MySQL系統產生的。

複製代碼

CREATE TABLE tk (
    col1 INT NOT NULL,
    col2 CHAR(5),
    col3 DATE
)
PARTITION BY LINEAR KEY (col1)
PARTITIONS 3;

複製代碼

 

1.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)  

複製代碼

複製代碼

分區的優點

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

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

3,進行大數據搜索時可以進行並行處理。

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

複製代碼

 

 

1.7 分區管理

a.刪除分區

  alter table user drop partion p4

b.新增分區

複製代碼

alter table user add partition(partition p4 values less than MAXVALUE);#新增range分區
alter table list_part add partition(partition p4 values in(25,26,27))   #新增list分區
alter table hash_part add partition partitions 4; # hash重新分區
alter table key_part add partition partitions 4; #key 重新分區
//子分區添加新分區,雖然我沒有指定子分區,但是系統會給子分區命名的 
alter table sub1_part add partition(partition p3 values less than MAXVALUE);
//range重新分區  
ALTER TABLE user REORGANIZE PARTITION p0,p1,p2,p3,p4 INTO (PARTITION p0 VALUES LESS THAN MAXVALUE);  
//list重新分區  
 ALTER TABLE list_part REORGANIZE PARTITION p0,p1,p2,p3,p4 INTO (PARTITION p0 VALUES in (1,2,3,4,5));  
 #hash和key分區不能用REORGANIZE,官方網站說的很清楚  

複製代碼

 

 

參考文獻:http://blog.csdn.net/yongchao940/article/details/55266603

       http://www.cnblogs.com/mliudong/p/3625522.html

2.分表管理

2.1 MySQL集羣

利用mysql cluster ,mysql proxy,mysql replication,drdb等等

複製代碼

有人會問mysql集羣,根分表有什麼關係嗎?雖然它不是實際意義上的分表,但是它啓到了分表的作用,做集羣的意義是什麼呢?爲一個數據庫減輕負擔,說白了就是減少sql排隊隊列中的sql的數量,
舉個例子:有10個sql請求,如果放在一個數據庫服務器的排隊隊列中,他要等很長時間,如果把這10個sql請求,分配到5個數據庫服務器的排隊隊列中,一個數據庫服務器的隊列中只有2個,
這樣等待時間是不是大大的縮短了呢?這已經很明顯了。所以我把它列到了分表的範圍以內;集羣我們在第三部分詳情說明;

優點:擴展性好,沒有多個分表後的複雜操作(php代碼)

缺點:單個表的數據量還是沒有變,一次操作所花的時間還是那麼多,硬件開銷大。

複製代碼

 

2.2 預先估計會出現的大數據並且訪問頻繁的表,將其分爲若干個表

我事先建100個這樣的表,message_00,message_01,message_02..........message_98,message_99.然後根據用戶的ID來判斷這個用戶的聊天信息放到哪張表裏面,

你可以用hash的方式來獲得,可以用求餘的方式來獲得,方法很多,各人想各人的吧。下面用hash的方法來獲得表名:

複製代碼

<?php  
function get_hash_table($table,$userid) {  
 $str = crc32($userid);  
 if($str<0){  
 $hash = "0".substr(abs($str), 0, 1);  
 }else{  
 $hash = substr($str, 0, 2);  
 }  
  
 return $table."_".$hash;  
}  
  
echo get_hash_table('message','user18991');     //結果爲message_10  
echo get_hash_table('message','user34523');    //結果爲message_13

優點:避免一張表出現幾百萬條數據,縮短了一條sql的執行時間


 

缺點:當一種規則確定時,打破這條規則會很麻煩,上面的例子中我用的hash算法是crc32,如果我現在不想用這個算法了,改用md5後,會使同一個用戶的消息被存儲到不同的表中,

   這樣數據亂套了。擴展性很差。

複製代碼

 

2.3 利用merge存儲引擎來實現分表

merge分表,分爲主表和子表,主表類似於一個殼子,邏輯上封裝了子表,實際上數據都是存儲在子表中的。

複製代碼

mysql> CREATE TABLE IF NOT EXISTS `user1` (  
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,  
 ->   `name` varchar(50) DEFAULT NULL,  
 ->   `sex` int(1) NOT NULL DEFAULT '0',  
 ->   PRIMARY KEY (`id`)  
 -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;  
Query OK, 0 rows affected (0.05 sec)  
  
mysql> CREATE TABLE IF NOT EXISTS `user2` (  
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,  
 ->   `name` varchar(50) DEFAULT NULL,  
 ->   `sex` int(1) NOT NULL DEFAULT '0',  
 ->   PRIMARY KEY (`id`)  
 -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;  
Query OK, 0 rows affected (0.01 sec)  
  
mysql> INSERT INTO `user1` (`name`, `sex`) VALUES('張映', 0);  
Query OK, 1 row affected (0.00 sec)  
  
mysql> INSERT INTO `user2` (`name`, `sex`) VALUES('tank', 1);  
Query OK, 1 row affected (0.00 sec)  
  
mysql> CREATE TABLE IF NOT EXISTS `alluser` (  
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,  
 ->   `name` varchar(50) DEFAULT NULL,  
 ->   `sex` int(1) NOT NULL DEFAULT '0',  
 ->   INDEX(id)  
 -> ) TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST AUTO_INCREMENT=1 ;  
Query OK, 0 rows affected, 1 warning (0.00 sec)

創建主表的時候有個INSERT_METHOD,指明插入方式,取值可以是:0 不允許插入;FIRST 插入到UNION中的第一個表; LAST 插入到UNION中的最後一個表。

通過主表查詢的時候,相當於將所有子表合在一起查詢。這樣並不能體現分表的優勢,建議還是查詢子表。


 

優點:擴展性好,並且程序代碼改動的不是很大


 

缺點:這種方法的效果比第二種要差一點,查詢性能不高


 

複製代碼

參考資料:http://blog.51yip.com/mysql/949.html

 

3.集羣

MySQL Proxy就是這麼一箇中間層代理,簡單的說,MySQL Proxy就是一個連接池,負責將前臺應用的連接請求轉發給後臺的數據庫,並且通過使用lua腳本,可以實現複雜的連接控制和過濾,從而實現讀寫分離和負載
平衡。對於應用來說,MySQL Proxy是完全透明的,應用則只需要連接到MySQL Proxy的監聽端口即可。當然,這樣proxy機器可能成爲單點失效,但完全可以使用多個proxy機器做爲冗餘,在應用服務器的連接池配置
中配置到多 個proxy的連接參數即可。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章