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 ;

查看一下tb_member表的結構:desc tb_member;

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,存儲引擎的使用不同,冷數據使用MyIsam 可以有更好的查詢數據。活躍數據,可以使用Innodb ,可以有更好的更新速度。
      2,對冷數據進行更多的從庫配置,因為更多的操作是查詢,這樣來加快查詢速度。對熱數據,可以相對有更多的主庫的橫向分表處理。
      3,對於一些特殊的活躍數據,也可以考慮使用memcache ,redis之類的緩存,等累計到一定量再去更新數據庫.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM