分表對(duì)于中小型網(wǎng)站來(lái)說(shuō)幾乎不會(huì)用到,但是在大型級(jí)數(shù)據(jù)來(lái)說(shuō)mysql分表是常見(jiàn)的事情了,下面我來(lái)介紹幾種常用的mysql分表方法,希望對(duì)大家有所幫助.
分表
1,做mysql集群,例如,利用mysql cluster,mysql proxy,mysql replication,drdb等等.
有人會(huì)問(wèn)mysql集群,根分表有什么關(guān)系嗎?雖然它不是實(shí)際意義上的分表,但是它啟到了分表的作用,做集群的意義是什么呢?為一個(gè)數(shù)據(jù)庫(kù)減輕負(fù)擔(dān),說(shuō)白了就是減少sql排隊(duì)隊(duì)列中的sql的數(shù)量,舉個(gè)例子:有10個(gè)sql請(qǐng)求,如果放在一個(gè)數(shù)據(jù)庫(kù)服務(wù)器的排隊(duì)隊(duì)列中,他要等很長(zhǎng)時(shí)間,如果把這10個(gè)sql請(qǐng)求,分配到5個(gè)數(shù)據(jù)庫(kù)服務(wù)器的排隊(duì)隊(duì)列中,一個(gè)數(shù)據(jù)庫(kù)服務(wù)器的隊(duì)列中只有2個(gè),這樣等待時(shí)間是不是大大的縮短了呢?這已經(jīng)很明顯了。所以我把它列到了分表的范圍以內(nèi),我做過(guò)一些mysql的集群:
linux mysql proxy 的安裝,配置,以及讀寫分離
mysql replication 互為主從的安裝及配置,以及數(shù)據(jù)同步
優(yōu)點(diǎn):擴(kuò)展性好,沒(méi)有多個(gè)分表后的復(fù)雜操作(php代碼)
缺點(diǎn):單個(gè)表的數(shù)據(jù)量還是沒(méi)有變,一次操作所花的時(shí)間還是那么多,硬件開(kāi)銷大。
2,預(yù)先估計(jì)會(huì)出現(xiàn)大數(shù)據(jù)量并且訪問(wèn)頻繁的表,將其分為若干個(gè)表
這種預(yù)估大差不差的,論壇里面發(fā)表帖子的表,時(shí)間長(zhǎng)了這張表肯定很大,幾十萬(wàn),幾百萬(wàn)都有可能。 聊天室里面信息表,幾十個(gè)人在一起一聊一個(gè)晚上,時(shí)間長(zhǎng)了,這張表的數(shù)據(jù)肯定很大。像這樣的情況很多。所以這種能預(yù)估出來(lái)的大數(shù)據(jù)量表,我們就事先分出個(gè)N個(gè)表,這個(gè)N是多少,根據(jù)實(shí)際情況而定。以聊天信息表為例:
我事先建100個(gè)這樣的表,message_00,message_01,message_02……….message_98,message_99.然后根據(jù)用戶的ID來(lái)判斷這個(gè)用戶的聊天信息放到哪張表里面,你可以用hash的方式來(lái)獲得,可以用求余的方式來(lái)獲得,方法很多,各人想各人的吧。下面用hash的方法來(lái)獲得表名:
查看復(fù)制打印?代碼如下:
- <?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);
- } //Vevb.com
- return $table."_".$hash;
- }
- echo get_hash_table('message','user18991'); //結(jié)果為message_10
- echo get_hash_table('message','user34523'); //結(jié)果為message_13
- ?>
說(shuō)明一下,上面的這個(gè)方法,告訴我們user18991這個(gè)用戶的消息都記錄在message_10這張表里,user34523這個(gè)用戶的消息都記錄在message_13這張表里,讀取的時(shí)候,只要從各自的表中讀取就行了。
優(yōu)點(diǎn):避免一張表出現(xiàn)幾百萬(wàn)條數(shù)據(jù),縮短了一條sql的執(zhí)行時(shí)間
缺點(diǎn):當(dāng)一種規(guī)則確定時(shí),打破這條規(guī)則會(huì)很麻煩,上面的例子中我用的hash算法是crc32,如果我現(xiàn)在不想用這個(gè)算法了,改用md5后,會(huì)使同一個(gè)用戶的消息被存儲(chǔ)到不同的表中,這樣數(shù)據(jù)亂套了。擴(kuò)展性很差。
3,利用merge存儲(chǔ)引擎來(lái)實(shí)現(xiàn)分表
我覺(jué)得這種方法比較適合,那些沒(méi)有事先考慮,而已經(jīng)出現(xiàn)了得,數(shù)據(jù)查詢慢的情況。這個(gè)時(shí)候如果要把已有的大數(shù)據(jù)量表分開(kāi)比較痛苦,最痛苦的事就是改代碼,因?yàn)槌绦蚶锩娴膕ql語(yǔ)句已經(jīng)寫好了,現(xiàn)在一張表要分成幾十張表,甚至上百?gòu)埍恚@樣sql語(yǔ)句是不是要重寫呢?舉個(gè)例子,我很喜歡舉子
mysql>show engines;的時(shí)候你會(huì)發(fā)現(xiàn)mrg_myisam其實(shí)就是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)
- mysql> select id,name,sex from alluser;
- +----+--------+-----+
- | id | name | sex |
- +----+--------+-----+
- | 1 | 張映 | 0 |
- | 1 | tank | 1 |
- +----+--------+-----+
- 2 rows in set (0.00 sec)
- mysql> INSERT INTO `alluser` (`name`, `sex`) VALUES('tank2', 0);
- Query OK, 1 row affected (0.00 sec)
- mysql> select id,name,sex from user2
- -> ;
- +----+-------+-----+
- | id | name | sex |
- +----+-------+-----+
- | 1 | tank | 1 |
- | 2 | tank2 | 0 |
- +----+-------+-----+
2 rows in set (0.00 sec)從上面的操作中,我不知道你有沒(méi)有發(fā)現(xiàn)點(diǎn)什么?假如我有一張用戶表user,有50W條數(shù)據(jù),現(xiàn)在要拆成二張表user1和user2,每張表25W條數(shù)據(jù),代碼如下:
- INSERT INTO user1(user1.id,user1.name,user1.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id <= 250000
- INSERT INTO user2(user2.id,user2.name,user2.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id > 250000
這樣我就成功的將一張user表,分成了二個(gè)表,這個(gè)時(shí)候有一個(gè)問(wèn)題,代碼中的sql語(yǔ)句怎么辦,以前是一張表,現(xiàn)在變成二張表了,代碼改動(dòng)很大,這樣給程序員帶來(lái)了很大的工作量,有沒(méi)有好的辦法解決這一點(diǎn)呢?辦法是把以前的user表備份一下,然后刪除掉,上面的操作中我建立了一個(gè)alluser表,只把這個(gè)alluser表的表名改成user就行了。但是,不是所有的mysql操作都能用的
a,如果你使用 alter table 來(lái)把 merge 表變?yōu)槠渌眍愋停降讓颖淼挠成渚捅粊G失了。取而代之的,來(lái)自底層 myisam 表的行被復(fù)制到已更換的表中,該表隨后被指定新類型。
b,網(wǎng)上看到一些說(shuō)replace不起作用,我試了一下可以起作用的,暈一個(gè)先,代碼如下:
- mysql> UPDATE alluser SET sex=REPLACE(sex, 0, 1) where id=2;
- Query OK, 1 row affected (0.00 sec)
- Rows matched: 1 Changed: 1 Warnings: 0
- mysql> select * from alluser;
- +----+--------+-----+
- | id | name | sex |
- +----+--------+-----+
- | 1 | 張映 | 0 |
- | 1 | tank | 1 |
- | 2 | tank2 | 1 |
- +----+--------+-----+
3 rows in set (0.00 sec)c,一個(gè) merge 表不能在整個(gè)表上維持 unique 約束。當(dāng)你執(zhí)行一個(gè) insert,數(shù)據(jù)進(jìn)入第一個(gè)或者最后一個(gè) myisam 表,取決于 insert_method 選項(xiàng)的值,mysql 確保唯一鍵值在那個(gè) myisam 表里保持唯一,但不是跨集合里所有的表.
d,當(dāng)你創(chuàng)建一個(gè) merge 表之時(shí),沒(méi)有檢查去確保底層表的存在以及有相同的機(jī)構(gòu)。當(dāng) merge 表被使用之時(shí),mysql 檢查每個(gè)被映射的表的記錄長(zhǎng)度是否相等,但這并不十分可靠。如果你從不相似的 myisam 表創(chuàng)建一個(gè) merge 表,你非常有可能撞見(jiàn)奇怪的問(wèn)題。
好困睡覺(jué)了,c和d在網(wǎng)上看到的,沒(méi)有測(cè)試,大家試一下吧。
優(yōu)點(diǎn):擴(kuò)展性好,并且程序代碼改動(dòng)的不是很大
缺點(diǎn):這種方法的效果比第二種要差一點(diǎn)
三,總結(jié)一下
上面提到的三種方法,我實(shí)際做過(guò)二種,第一種和第二種。第三種沒(méi)有做過(guò),所以說(shuō)的細(xì)一點(diǎn)。哈哈。做什么事都有一個(gè)度,超過(guò)個(gè)度就過(guò)變得很差,不能一味的做數(shù)據(jù)庫(kù)服務(wù)器集群,硬件是要花錢買的,也不要一味的分表,分出來(lái)1000表,mysql的存儲(chǔ)歸根到底還以文件的形勢(shì)存在硬盤上面,一張表對(duì)應(yīng)三個(gè)文件,1000個(gè)分表就是對(duì)應(yīng)3000個(gè)文件,這樣檢索起來(lái)也會(huì)變的很慢,我的建議是:
方法1和方法2結(jié)合的方式來(lái)進(jìn)行分表
方法1和方法3結(jié)合的方式來(lái)進(jìn)行分表
我的二個(gè)建議適合不同的情況,根據(jù)個(gè)人情況而定,我覺(jué)得會(huì)有很多人選擇方法1和方法3結(jié)合的方式.
新聞熱點(diǎn)
疑難解答
圖片精選