MySQL之分庫分表分區
一、分庫
爲了解決單臺服務器的性能問題,噹噹單臺數據庫服務器無法支撐當前的數據量時,就需要根據業務邏輯緊密程度把表分成幾撮,分別放在不同的數據庫服務器中以降低單臺服務器的負載。
分庫策略也可以:垂直拆分和水平拆分
垂直拆分,按照業務和功能劃分,把數據分別放到不同的數據庫
水平拆分 把一張表的數據劃分到不同的數據庫,兩個數據庫的表結構一樣。
比如一個論壇系統的數據庫因當前服務器性能無法滿足需要進行分庫。 先垂直切分,按業務邏輯把用戶相關數據表比如用戶信息、積分、用戶間私信等放入user數據庫;論壇相關數據表比如板塊,帖子,回覆等放入forum數據庫,兩個數據庫放在不同服務器上。
所以:分庫的目的是降低單臺服務器負載,切分原則是根據業務緊密程度拆分,缺點是跨數據庫無法聯表查詢
二、分表
當數據表中的數據量超級大時。很多時候索引就力不從心。服務器需要根據索引掃描的結果返回表,再查詢所有符合條件的記錄。如果數據量巨大,這將產生大量隨機I/O.逐漸數據庫的響應時間將大到不可接受的程度
1.垂直分表
切分原則:把不常用或業務邏輯不緊密或存儲內容比較多的字段分到新的表中可使表存儲更多數據。即:把表中的字段進行拆分,即一張字段比較多的表拆分爲多張表,這樣使得行數據變小。
拆分建議:
- 將不常用的字段單獨拆分到另外一張擴展表。比如用戶家庭地址
將大文本的字段單獨拆分到另外一張擴張表。例如blob和text字符串類型的字段,這樣可以減少客戶端程序和數據庫之間的網絡傳輸字節數。
將不經常修改的字段放在同一張表中,將經常修改的字段放在另一張表中。例如最後登錄時間.這個字段還會導致查詢緩存被清空。建議放置另一個表中
對於需要經常關聯的字段,建議放在同一張表中。
2.水平分表
水平拆表,把表的行進行拆分。因爲表的行數超過幾百萬行時,就會變慢,這時可以把一張表拆分成多張表來存放。 常用的策略:
1. 取模分表
$uid = 8;
$member_table = 'member'.$uid%5;
$sql = "select * from {$member_table}";
//查看所有會員信息
$table = ['member0','member1','member2','member3','member4','member'];
foreach($table as $tab){
$sql .= " select * from {$tab} union";
}
$sql = substr($sql,0,-5);
- 時間維度分表
Like:
log_2014-12-01_2014-12-15
log_2014-12-16_2014-12-31
log_2015-01-01_2015-01-16
log_2015-01-17_2015-02-01
log_2015-02-02_2015-02-17
log_2015-02-18_2015-03-05
log_2015-03-06_2015-03-21
log_2015-03-22_2015-04-06
- 自定義Hash分表
-最初的userby表,擴展爲100張相同表結構的userbuy_index表
-首先對userid進行hash計算,得到hash值,該hash值必然是0-99,目的是將對應的userid數據,寫入到同一張分表中
-自定義hash算法
function getStringHash($string, $tab_count)
{
$unsign = sprintf('%u', crc32($string));
if ($unsign > 2147483647) // sprintf u for 64 & 32 bit
{
$unsign -= 4294967296;
}
return abs($unsign) % $tab_count;
}
實際上,垂直拆分後的表依然存在單表數據量過大的問題,需要進行水平拆分。
分區
所謂分區,就是把一個數據表的文件和索引分散存儲在不同的物理文件中。(5.1+)
//確認是否支持分區
SHOW VARIABLES LIKE '%partition%'
分區類型:Range、List、Hash、Key。range最常用
MySQL通過分區把數據保存到不同的數據文件裏,同時索引也是分區的。相對未分區的表來說,分區後單獨的數據文件和索引文件的大小都明顯降低,效率則明顯提升。