1.分區php
mysql數據庫中的數據是以文件的形勢存在磁盤上的,默認放在/mysql/data下面(能夠經過my.cnf中的datadir來查看),一張表主要對應着三個文件,一個是frm存放表結構的,一個是myd存放表數據的, 一個是myi存表索引的。若是一張表的數據量太大的話,那麼myd,myi就會變的很大,查找數據就會變的很慢,這個時候咱們能夠利用mysql的分區功能, 在物理上將這一張表對應的三個文件,分割成許多個小塊,這樣呢,咱們查找一條數據時,就不用所有查找了,只要知道這條數據在哪一塊,而後在那一塊找就好了。 若是表的數據太大,可能一個磁盤放不下,這個時候,咱們能夠把數據分配到不一樣的磁盤裏面去
分區的二種方式html
a,橫向分區mysql
什麼是橫向分區呢?就是橫着來分區了,舉例來講明一下,假若有100W條數據,分紅十份,前10W條數據放到第一個分區,第二個10W條數據放到第二個分區,依此類推。也就是把表分紅了十分,根用merge來分表,有點像哦。取出一條數據的時候,這條數據包含了表結構中的全部字段,也就是說橫向分區,並無改變表的結構。算法
b,縱向分區sql
什麼是縱向分區呢?就是豎來分區了,舉例來講明,在設計用戶表的時候,開始的時候沒有考慮好,而把我的的全部信息都放到了一張表裏面去,這樣這個表裏面就會有比較大的字段,如我的簡介,而這些簡介呢,也許不會有好多人去看,因此等到有人要看的時候,在去查找,分表的時候,能夠把這樣的大字段,分開來。數據庫
mysql提供的分區屬於第一種,橫向分區,而且細分紅不少種方式:服務器
1.1 MySQL5.1及以上支持分區功能less
查看是否支持分區
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的鏈接參數便可。
參考資料:http://www.cnblogs.com/phpstudy2015-6/p/6706465.html
http://blog.51yip.com/mysql/399.html