1. 程式人生 > >mysql使用MRG_MyISAM(MERGE)實現水平分表

mysql使用MRG_MyISAM(MERGE)實現水平分表

在MySql中資料的優化尤其是大資料量的優化是一門很大的學問,當然其它資料庫也是如此,即使你不是DBA,做為一名程式設計師掌握一些基本的優化資訊,也可以讓你在自己的程式開發中受益匪淺。當然資料庫的優化有很多的方方面面,本篇主要講,Mysql的水平分表技術,也可以說是其技術的其中之一。

在使用水平分表時,首先問下自己幾個問題。

一、為什麼要水平分表?

簡而言之,當單表資料量過大時,無法對其進行有效的維護,以及查詢速度嚴重變慢時,我們就需要對其時行水平分表

二、什麼時候需要水平分表?

在資料庫結構的設計中,需要充分考慮後期資料的增長量和增長速度,如果後期的資料增長量過快,以及後期資料量巨大,就需要使用水平分表。

三、怎樣實現水平分表?

其實水平分表的方法,很多,但個人覺得結合程式的增刪改查,本篇介紹的方法MRG_MySIAM儲存引擎(MERGE儲存引擎)個人覺得還是比較簡單方便的,雖然效能方面與其它分表技術相比可能不是第一,但就使用程式對其的操控性來說,個人覺得還是很不錯的。

 

MERGE儲存引擎基本介紹和使用規範說明【以下截自MySql手冊】:

MERGE儲存引擎,也被認識為MRG_MyISAM引擎,是一個相同的可以被當作一個來用的MyISAM表的集合。“相同”意味著所有表同樣的列和索引資訊。你不能合併列被以不同順序列於其中的表,沒有恰好同樣列的表,或有不同順序索引的表。而且,任何或者所有的表可以用myisampack

來壓縮。表選項的差異,比如AVG_ROW_LENGTH, MAX_ROWS或PACK_KEYS都不重要。

當你建立一個MERGE表之時,MySQL在磁碟上建立兩個檔案。檔名以表的名字開始,並且有一個副檔名來指明檔案型別。一個.frm檔案儲存表定義,一個.MRG檔案包含被當作一個來用的表的名字。這些表作為MERGE表自身,不必要在同一個資料庫中。

你可以對錶的集合用SELECT, DELETE, UPDATE和INSERT。你必須對你對映到一個MERGE表的這些表有SELECT, UPDATE和DELETE 的許可權。

如果你DROP MERGE表,你僅在移除MERGE規格。底層表沒有受影響。

當你建立一個MERGE表之時,你必須指定一個UNION=(list-of-tables)子句,它說明你要把哪些表當作一個來用。如果你想要對MERGE表的插入發生在UNION列表中的第一個或最後一個表上,你可以選擇地指定一個INSERT_METHOD選項。使用FIRST或LAST值使得插入被相應地做在第一或最後一個表上。如果你沒有指定INSERT_METHOD選項,或你用一個NO值指定該選項。往MERGE表插入記錄的試圖導致錯誤。

大致瞭解了MERGE儲存引擎的基本介紹後,就讓我們真正開始動手吧。

在分表的我們必須考慮如下問題:

1、根據什麼樣的規則來實現分表,即通過什麼樣的規則來插入不同的資料表?

2、即使分表成功,那麼程式對其的處理是否簡潔?

下面以下例項來說明,

假設我們有個郵件伺服器,需要儲存很多很多使用者的郵件,為了解決後期資料量具大問題,我們就需要使用水平分表技術。

以什麼樣的規則來實現分表,分表資料如何確定?

首先我們必須大概估算以後的資料量會多大,分多少張表比較合適,從而來確定分表規則。

以我的情況為例,

我覺得以郵件的傳送時間來計算,按天來劃分,分為31張表比較合適。

那麼我的分表規則,則如下設計,:

    email為主表,email_X為子表,先建立子表,結構與主表相同,在建立子表時注意要將ENGINE=MRG_MyISAM替換為ENGINE=MyISAM,否則會出現Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist的錯誤提示,不能對主表進行查詢

CREATE TABLE `email` (

  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,

  `euid` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT '帳號ID',

  `uid` char(50) NOT NULL COMMENT '郵件UID',

  `reciever` char(255) NOT NULL COMMENT '收件人',

  `sender` char(255) NOT NULL COMMENT '傳送人',

  `sendTime` int(10) unsigned NOT NULL DEFAULT '0',

  `sendTitle` char(100) NOT NULL COMMENT '主題 ',

  `type` char(50) NOT NULL COMMENT '型別',

  PRIMARY KEY (`id`)

) ENGINE=MRG_MyISAM

 DEFAULT CHARSET=utf8 

UNION=(`email_1`,`email_2`,`email_3`,`email_4`,`email_5`,`email_6`,`email_7`,`email_8`,`email_9`,`email_10`,`email_11`,`email_12`,`email_13`,`email_14`,`email_15`,`email_16`,`email_17`,`email_18`,`email_19`,`email_20`,`email_21`,`email_22`,`email_23`,`email_24`,`email_25`,`email_26`,`email_27`,`email_28`,`email_29`,`email_30`,`email_31`);

首先建立一張MERGE儲存型別的主表,

然後再批量建立31張MyISAM儲存型別的資料表。

OK,此時建立完成後,我們需要做的是什麼?

當然,第一步肯定是寫入資料。此時我們的分表規則就有了用武之地了。

$sql = "INSERT INTO email_{$ruleNum}(....) VALUES(.....);"

 

此時完全可以正確的寫入,並且在Email表中也會存在,是不是很OK。

但別高興太早,我們要做的遠遠不止這些。

首先,因為ID是Auto_Increment,你完全可以不用管,因為每次插入不同的資料表都會有不同的ID,但問題是當你在EMAil這個Merge型別表中檢視時你會發現,會有很多重複的ID,因為每張表的ID在email表中展現可能會有大量重複。這對我們修改和刪除會有極大的影響,如果沒有惟的ID,預設修改是根據排序來分別的,當然不可以。

所以在資料寫入時,我們必須還要手動增加ID,來保證整個資料的ID都是惟一的。

方法當然有很多種,簡單介紹下我的做法,

我直接新建了一張表就一個欄位:

在每次新增完成資料後,都會使用觸發器自動將此表中的資料值+1,而在每次讀取時,先讀取此表,獲取下一個ID,這樣就能保證資料ID永遠惟一。

PS:也可以將此ID值存入檔案,前提是在不會丟失的情況下。或其它都OK。

寫入問題解決後,就剩下UPDATE,DELETE,SELECT了,這些現在都已不是問題,我們直接操作Email這個Merge型別表即可,(Mysql手冊也有詳細的介紹,可自行檢視)

INSERT:

SELECT * FROM eamil where ($where) limit 20,10;

 

UPDATE:

UPDATE email SET username='$username' WHERE id=10

 

DELETE:

DELETE FROM email WHERE id=11

 

這只是一種MySql的水平分表方法,如果資料表較少的話,也可以使用

union 聯合查詢來實現資料表分表聯合查詢。

其它方法,網上也有很多,可自行檢視。