數據庫分表算法


在大中型項目中,在數據庫設計的時候,考慮到數據庫最大承受數據量,通常會把數據庫或者數據表水平切分,以降低單個庫,單個表的壓力。這里介紹兩個項目中 常用的數據表切分方法。當然這些方法都是在程序中?使用一定的技巧來路由到具體的表的。首先我們要確認根據什么來水平切分?在我們的系統(SNS)中,用 戶的UID貫穿系統,唯一自增長,根據這個字段分表,再好不過。

function getTable( $uid ){
  $ext =  substr ( md5($uid) ,0 ,2 );
  return "user_".$ext;
}

/*
 * 參    數:$project 字符串	項目
 *			 $group 數組	待進行分表的字段及值
 *			 &$tables	數組	目前已經分的表,以值址方式傳參
 *			 $length 整型	截取字符串前幾位,此項與分表的數據密切相關,默認為2
 * 功    能:分表引擎
 */
function engineSplitTable($project, $group, &$tables, $length = MD5_PREFIX_LENGTH) {
	$keys = array_keys($group);
	$values = array_values($group);
	$sequence = substr(md5(implode('', $values)), 0, $length);
	
	$table = $project.'_'.implode('_', $keys).'_'.$sequence;
	
	if(isset($tables[$table])) {
	} else {
		$tables[$table] = array('textFile' => '', 'fields' => '', 'counter' => 0);
	}
	return $table;
}

 注意:md5出來的字串僅包含0~9a~f,你可以把每位看成一個16進制的數字。那么 substr ( md5($uid) ,0 ,2 ) 出來的范圍就是16進制的 00~ff,轉成10進制就是 0~16*16

md5后的各位實際上是: 10個數字 + 6個字符的組合  = 16

md5后的值要么全是小寫字母,要么全是大寫字母,不會出現混合的情況,所以字母就只有 a-f || A-F 這兩種之一

 

通過這個技巧,我們可以將不同的UID分散到256中用戶表中,分別是user_00,user_01 ...... user_ff。因為UID是數字且遞增,根據md5的算法,可以將用戶數據幾乎很均勻的分別到不同的user表中。

但是這里有個問題是,如果我們的系統的用戶越來越多,勢必單張表的數據量越來越大,而且根據這種算法無法擴展表,這又會回到文章開頭出現的問題了。

一般情況下:設計分表之初就應該考慮到該表能達到的最大數據量,選擇分多少張表,如果真的超過了預估,可以考慮集群。

方法二:使用移位

public function getTable( $uid ) {
 return "user_" . sprintf( "d", ($uid >> 20) );
}

 這里,我們將uid向右移動20位,這樣我們就可以把大約前100萬的用戶數據放在第一個表user_0000,第二個100萬的用戶數據放在第二個表 user_0001中,這樣一直下去,如果我們的用戶越來越多,直接添加用戶表就行了。由於我們保留的表后綴是四位,這里我們可以添加1萬張用戶表,即 user_0000,user_0001 ...... user_9999。一萬張表,每張表100萬數據,我們可以存100億條用戶記錄。當然,如果你的用戶數據比這還多,也不要緊,你只要改變保留表后綴來 增加可以擴展的表就行了,如如果有1000億條數據,每個表存100萬,那么你需要10萬張表,我們只要保留表后綴為6位即可。

/**
 * 根據UID分表算法
 * 
 * @param int $uid  //用戶ID
 * @param int $bit    //表后綴保留幾位
 * @param int $seed //向右移動位數
 */
function getTable( $uid , $bit , $seed ){
  return "user_" . sprintf( "%0{$bit}d" , ($uid >> $seed) );
}

 

總結

上面兩種方法,都要對我們當前系統的用戶數據量做出可能最大的預估,並且對數據庫單個表的最大承受量做出預估。

比如第二種方案,如果我們預估我們系統的用戶是100億,單張表的最優數據量是100萬,那么我們就需要將UID移動20來確保每個表是100萬的數據,保留用戶表(user_xxxx)四位來擴展1萬張表。

又如第一種方案,每張表100萬,md5后取前兩位,就只能有256張表了,系統總數據庫就是:256*100萬;如果你系統的總數據量的比這還多,那你實現肯定要MD5取前三位或者四位甚至更多位了。

兩種方法都是將數據水平切分到不同的表中,相對第一種方法,第二種方法更具擴展性。

 

參考:http://www.nowamagic.net/librarys/veda/detail/1528

http://lampblog.org/285.html

http://blog.csdn.net/hhq163/article/details/6219221


免責聲明!

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



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