項目開(kāi)發(fā)中,我們的數據庫數據越來(lái)越大,隨之而來(lái)的是單個(gè)表中數據太多。以至于查詢(xún)書(shū)讀變慢,而且由于表的鎖機制導致應用操作也搜到嚴重影響,出現了數據庫性能瓶頸。
當出現這種情況時(shí),我們可以考慮分表,即將單個(gè)數據庫表進(jìn)行拆分,拆分成多個(gè)數據表,然后用戶(hù)訪(fǎng)問(wèn)的時(shí)候,根據一定的算法,讓用戶(hù)訪(fǎng)問(wèn)不同的表,這樣數據分散到多個(gè)數據表中,減少了單個(gè)數據表的訪(fǎng)問(wèn)壓力。提升了數據庫訪(fǎng)問(wèn)性能。
我們可以進(jìn)行簡(jiǎn)單的設想:現在有一個(gè)表products存儲產(chǎn)品信息,現在有100萬(wàn)用戶(hù)在線(xiàn)訪(fǎng)問(wèn),就要進(jìn)行至少100萬(wàn)次請求,現在我們如果將它分成100個(gè)表即products0~~products99,那么利用一定的算法我們就分擔了單個(gè)表的訪(fǎng)問(wèn)壓力,每個(gè)表只有1萬(wàn)個(gè)請求(當然,這是理想情況下?。?/p>
實(shí)現mysql 分表的關(guān)鍵在于:設計良好的算法來(lái)確定"什么時(shí)候情況下訪(fǎng)問(wèn)什么(哪個(gè))表"。
下面我們先來(lái)實(shí)現一個(gè)簡(jiǎn)單的mysql分表演示:這里使用MERGE分表法
1,創(chuàng )建一個(gè)完整表存儲著(zhù)所有的成員信息
create table member(id bigint auto_increment primary key,name varchar(20),sex tinyint not null default '0')engine=myisam default charset=utf8 auto_increment=1;
加入點(diǎn)數據:
insert into member(id,name,sex) values (1,'jacson','0');
insert into member(name,sex) select name,sex from member;
第二條語(yǔ)句多執行幾次就有了很多數據。
2,下面我們進(jìn)行分表:這里我們分兩個(gè)表tb_member1,tb_member2
DROP table IF EXISTS tb_member1;create table tb_member1( id bigint primary key auto_increment , name varchar(20), sex tinyint not null default '0')ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
DROP table IF EXISTS tb_member2;create table tb_member2( id bigint primary key auto_increment , name varchar(20), sex tinyint not null default '0')ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
//創(chuàng )建tb_member2也可以用下面的語(yǔ)句 create table tb_member2 like tb_member1;
3,創(chuàng )建主表tb_member
DROP table IF EXISTS tb_member;
create table tb_member(
id bigint primary key auto_increment ,
name varchar(20),
sex tinyint not null default '0'
)ENGINE=MERGE UNION=(tb_member1,tb_member2) INSERT_METHOD=LAST CHARSET=utf8 AUTO_INCREMENT=1 ;
查看一下tb_member表的結構:desc tb_member;

4,接下來(lái),我們把數據分到兩個(gè)分表中去:
insert into tb_member1(id,name,sex) select id,name,sex from member where id%2=0;
insert into tb_member2(id,name,sex) select id,name,sex from member where id%2=1;
查看一下主表的數據:select * from tb_member;

注意:總表只是一個(gè)外殼,存取數據發(fā)生在一個(gè)一個(gè)的分表里面。
ps:創(chuàng )建主表時(shí)可能會(huì )出現下面的錯誤:
ERROR 1168 (HY000): Unable to open underlying table which is differently defined
or of non-MyISAM type or doesn't exist
若遇到上面這種錯誤,一般從兩方面來(lái)排查:(從這兩方面一般可以解決這個(gè)問(wèn)題,本人也遇到了。)
1,查看上面的分表數據庫引擎是不是MyISAM.
2,查看分表與指標的字段定義是否一致。
分表的大概過(guò)程和步驟就是這樣的,下面我們來(lái)看看分表的算法實(shí)現:
假設現在有一個(gè)應用系統可能會(huì )有100億的用戶(hù)量,另外一個(gè)表一般存儲量在不超過(guò)100萬(wàn)的時(shí)候基本能保持良好性能,計算下來(lái),我們需要1萬(wàn)張表,即分表為1萬(wàn)個(gè)表。
我們可以設計成:user_0~user_9999
在用戶(hù)表里面我們有唯一的標示是用戶(hù)id,我們尅設計一個(gè)小算法來(lái)實(shí)現用戶(hù)id與訪(fǎng)問(wèn)表名的對應:
function getTable($id)
{
return 'user_'.sprintf('%d',($id >>20));
}
解釋一下:($id >> 20)表示將向右移位20位,(向右移動(dòng)一位標示減少一半),printf('%d',$data)標示將數據按照十進(jìn)制輸出。
即id為1~1048575(2的20次冪-1)時(shí)均訪(fǎng)問(wèn)user_0,1048576~2097152時(shí)訪(fǎng)問(wèn)user_1,以此類(lèi)推.....
那么問(wèn)題來(lái)了,如果用戶(hù)更多怎么辦,現在需要一個(gè)可擴展的方法:
聯(lián)系客服