1. 程式人生 > >mysql資料庫分表及實現

mysql資料庫分表及實現

專案開發中,我們的資料庫資料越來越大,隨之而來的是單個表中資料太多。以至於查詢書讀變慢,而且由於表的鎖機制導致應用操作也搜到嚴重影響,出現了資料庫效能瓶頸。

    當出現這種情況時,我們可以考慮分表,即將單個數據庫表進行拆分,拆分成多個數據表,然後使用者訪問的時候,根據一定的演算法,讓使用者訪問不同的表,這樣資料分散到多個數據表中,減少了單個數據表的訪問壓力。提升了資料庫訪問效能。

    我們可以進行簡單的設想:現在有一個表products儲存產品資訊,現在有100萬用戶線上訪問,就要進行至少100萬次請求,現在我們如果將它分成100個表即products0~~products99,那麼利用一定的演算法我們就分擔了單個表的訪問壓力,每個表只有1萬個請求(當然,這是理想情況下!)

實現mysql 分表的關鍵在於:設計良好的演算法來確定"什麼時候情況下訪問什麼(哪個)表"。

下面我們先來實現一個簡單的mysql分表演示:這裡使用MERGE分表法

1,建立一個完整表儲存著所有的成員資訊

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;

加入點資料:

insert into member(id,name,sex) values (1,'jacson','0');
insert into member(name,sex) select name,sex from member;

第二條語句多執行幾次就有了很多資料。

2,下面我們進行分表:這裡我們分兩個表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 ; 
//建立tb_member2也可以用下面的語句  create table tb_member2 like tb_member1;

  3,建立主表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 ;

4,接下來,我們把資料分到兩個分表中去:

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;

注意:總表只是一個外殼,存取資料發生在一個一個的分表裡面。

ps:建立主表時可能會出現下面的錯誤:

ERROR 1168 (HY000): Unable to open underlying table which is differently defined

or of non-MyISAM type or doesn't exist

若遇到上面這種錯誤,一般從兩方面來排查:(從這兩方面一般可以解決這個問題,本人也遇到了。)

  1,檢視上面的分表資料庫引擎是不是MyISAM.

  2,檢視分表與指標的欄位定義是否一致。

分表的大概過程和步驟就是這樣的,下面我們來看看分表的演算法實現:

假設現在有一個應用系統可能會有100億的使用者量,另外一個表一般儲存量在不超過100萬的時候基本能保持良好效能,計算下來,我們需要1萬張表,即分表為1萬個表。

我們可以設計成:user_0~user_9999

在使用者表裡面我們有唯一的標示是使用者id,我們尅設計一個小演算法來實現使用者id與訪問表名的對應:

function getTable($id)
{
   return 'user_'.sprintf('%d',($id >>20));
}

解釋一下:($id >> 20)表示將向右移位20位,(向右移動一位標示減少一半),printf('%d',$data)標示將資料按照十進位制輸出。

               即id為1~1048575(2的20次冪-1)時均訪問user_0,1048576~2097152時訪問user_1,以此類推.....

那麼問題來了,如果使用者更多怎麼辦,現在需要一個可擴充套件的方法:

function getTable($id,$bit,$seed){

   return 'user_'.sprintf('%0{$bit}d',($id >> $seed));

}

其中:$id為使用者id,$bit標示表字尾的位數,$seed表示要移位的位數即:單個表能儲存的記錄條數。

這樣就可以任意分表了。

注意點:

1、在資料庫新增時,需要具體針對單表進行插入。如果插入總表,總表預設將記錄插入最後一張表或者第一張表中(根據INSERT_METHOD=LAST還是first

2、資料讀取、更新、刪除直接從總表操作即可