日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 分库分表的方法

發布時間:2024/9/20 数据库 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 分库分表的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

來源:http://hudeyong926.iteye.com/blog/902801

一,先說一下為什么要分表

當一張的數據達到幾百萬時,你查詢一次所花的時間會變多,如果有聯合查詢的話,我想有可能會死在那兒了。分表的目的就在于此,減小數據庫的負擔,縮短查詢時間。

根據個人經驗,mysql執行一個sql的過程如下:
1,接收到sql;2,把sql放到排隊隊列中 ;3,執行sql;4,返回執行結果。在這個執行過程中最花時間在什么地方呢?第一,是排隊等待的時間,第二,sql的執行時間。其實這二個是一回事,等待的同時,肯定有sql在執行。所以我們要縮短sql的執行時間。

?

mysql中有一種機制是表鎖定和行鎖定,為什么要出現這種機制,是為了保證數據的完整 性,我舉個例子來說吧,如果有二個sql都要修改同一張表的同一條數據,這個時候怎么辦呢,是不是二個sql都可以同時修改這條數據呢?很顯然mysql 對這種情況的處理是,一種是表鎖定(myisam存儲引擎),一個是行鎖定(innodb存儲引擎)。表鎖定表示你們都不能對這張表進行操作,必須等我對 表操作完才行。行鎖定也一樣,別的sql必須等我對這條數據操作完了,才能對這條數據進行操作。如果數據太多,一次執行的時間太長,等待的時間就越長,這 也是我們為什么要分表的原因。

?

垂直分割

就是將一個大表分為多個小表.把主碼和一些列放到一個表,然后把主碼和另外的列放到另一個表中。
如果一個表中某些列常用,而另外一些列不常用,則可以采用垂直分割,另外垂直分割可以使得數據行變小,一個數據頁就能存放更多的數據,在查詢時就會減少I/O次數。其缺點是需要管理冗余列,查詢所有數據需要join操作。比如物料有很多屬性,不同的部門有不同的屬性需求,比如財務部門有財務的屬性要求,采購部門有采購的屬性要求,按部門要求不同拆分為不同的表,僅將基本的公共屬性放在主表中,根據不同的部門要求建不同的表及查詢視圖,性能要好一些

二,分表

1,做mysql集群,例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等

有人會問mysql集群,根分表有什么關系嗎?雖然它不是實際意義上的分表,但是它啟到 了分表的作用,做集群的意義是什么呢?為一個數據庫減輕負擔,說白了就是減少sql排隊隊列中的sql的數量,舉個例子:有10個sql請求,如果放在一 個數據庫服務器的排隊隊列中,他要等很長時間,如果把這10個sql請求,分配到5個數據庫服務器的排隊隊列中,一個數據庫服務器的隊列中只有2個,這樣 等待時間是不是大大的縮短了呢?這已經很明顯了。所以我把它列到了分表的范圍以內,我做過一些mysql的集群:

linux mysql proxy 的安裝,配置,以及讀寫分離

mysql replication 互為主從的安裝及配置,以及數據同步

優點:擴展性好,沒有多個分表后的復雜操作(php代碼)

缺點:單個表的數據量還是沒有變,一次操作所花的時間還是那么多,硬件開銷大。

2,預先估計會出現大數據量并且訪問頻繁的表,將其分為若干個表

使用MD5哈希

做法是對UID進行md5加密,然后取前幾位(我們這里取前兩位),然后就可以將不同的UID哈希到不同的用戶表(user_xx)中了

Java代碼??
  • <?php??
  • function?get_hash_table($table,?$userid)??
  • {??
  • ????$str?=?crc32($userid);??
  • ????if?($str?<?0)?{??
  • ????????$hash?=?"0"?.?substr(abs($str),?0,?1);??
  • ????}?else?{??
  • ????????$hash?=?substr($str,?0,?2);??
  • ????}??
  • ????return?$table?.?"_"?.?$hash;??
  • }??
  • //echo?get_hash_table('message',?'user18991');?//結果為message_10??
  • //echo?get_hash_table('message',?'user34523');?//結果為message_13??
  • function?calc_hash_db($u,?$s?=?4)?{??
  • ????$h?=?sprintf("%u",?crc32($u));??
  • ????$h1?=?intval(fmod($h,?$s));??
  • ????return?$h1;??
  • }??
  • ??
  • for?($i?=?1;?$i?<?40;?$i++)?{??
  • ????echo?calc_hash_tbl($i);??
  • ????echo?"<br>";??
  • ????echo?calc_hash_db($i);??
  • ????echo?"<br>";??
  • }??
  • ??
  • function?calc_hash_tbl($u,?$n?=?256,?$m?=?16)?{??
  • ????$h?=?sprintf("%u",?crc32($u));??
  • ????$h1?=?intval($h?/?$n);??
  • ????$h2?=?$h1?%?$n;??
  • ????$h3?=?base_convert($h2,?10,?$m);??
  • ????$h4?=?sprintf("%02s",?$h3);??
  • ??
  • ????return?$h4;??
  • }??
  • #################??
  • function?getTable(?$uid?){??
  • ????$ext?=?substr?(?md5($uid)?,0?,2?);??
  • ????return?"user_".$ext;??
  • }??
  • ###################??
  • private?function?getDbNo($email)??
  • {??
  • ????$m?=?md5($email);??
  • ????$n?=?hexdec(substr($m,?0,?16));??
  • ????$tableNo?=?fmod($n,?1000);??
  • ????$dbNo?=?$tableNo?%?100;??
  • ????return?array($dbNo,?$tableNo);??
  • }??
  • 通過這個技巧,我們可以將不同的UID分散到256中用戶表中,分別是user_00,user_01 ……? ? user_ff。因為UID是數字且遞增,根據md5的算法,可以將用戶數據幾乎很均勻的分別到不同的user表中。

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

    使用移位

    Java代碼??
  • /**?
  • ?*?根據UID分表算法?
  • ?*?
  • ?*?@param?int?$uid??//用戶ID?
  • ?*?@param?int?$bit????//表后綴保留幾位?
  • ?*?@param?int?$seed?//向右移動位數?
  • ?*/??
  • function?getTable(?$uid?,?$bit?,?$seed?){??
  • ????return?"user_"?.?sprintf(?"%0{$bit}d"?,?($uid?>>?$seed)?);??
  • ????return?"user_"?.?sprintf(?"%04d",?($uid?>>?20)?);??
  • ??
  • }??
  • 這里,我們將uid向右移動20位,這樣我們就可以把大約前100萬的用戶數據放在第一個表user_0000,第二個100萬的用戶數據放在第二 個表user_0001中,這樣一直下去,如果我們的用戶越來越多,直接添加用戶表就行了。由于我們保留的表后綴是四位,這里我們可以添加1萬張用戶表, 即user_0000,user_0001 …… user_9999。一萬張表,每張表100萬數據,我們可以存100億條用戶記錄。當然,如果你的用戶數據比這還多,也不要緊,你只要改變保留表后綴來 增加可以擴展的表就行了,如如果有1000億條數據,每個表存100萬,那么你需要10萬張表,我們只要保留表后綴為6位即可。

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

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

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

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

    ?

    3,利用merge存儲引擎來實現分表

    我覺得這種方法比較適合,那些沒有事先考慮,而已經出現了得,數據查詢慢的情況。這個時 候如果要把已有的大數據量表分開比較痛苦,最痛苦的事就是改代碼,因為程序里面的sql語句已經寫好了,現在一張表要分成幾十張表,甚至上百張表,這樣 sql語句是不是要重寫呢?舉個例子,我很喜歡舉子

    mysql>show engines;的時候你會發現mrg_myisam其實就是merge。

    Java代碼??
  • CREATE?TABLE?IF?NOT?EXISTS?`user1`?(????
  • ????`id`?int(11)?NOT?NULL?AUTO_INCREMENT,????
  • ????`name`?varchar(50)?DEFAULT?NULL,????
  • ????`sex`?int(1)?NOT?NULL?DEFAULT?'0',????
  • ????PRIMARY?KEY?(`id`)????
  • ??)?ENGINE=MyISAM??DEFAULT?CHARSET=utf8?AUTO_INCREMENT=1?;????
  • Query?OK,?0?rows?affected?(0.05?sec)??
  • ??
  • ?CREATE?TABLE?IF?NOT?EXISTS?`user2`?(????
  • ????`id`?int(11)?NOT?NULL?AUTO_INCREMENT,????
  • ????`name`?varchar(50)?DEFAULT?NULL,????
  • ????`sex`?int(1)?NOT?NULL?DEFAULT?'0',????
  • ????PRIMARY?KEY?(`id`)????
  • ??)?ENGINE=MyISAM??DEFAULT?CHARSET=utf8?AUTO_INCREMENT=1?;????
  • Query?OK,?0?rows?affected?(0.01?sec)??
  • ??
  • mysql>?INSERT?INTO?`user1`?(`name`,?`sex`)?VALUES('張映',?0);??
  • Query?OK,?1?row?affected?(0.00?sec)??
  • ??
  • mysql>?INSERT?INTO?`user2`?(`name`,?`sex`)?VALUES('tank',?1);??
  • Query?OK,?1?row?affected?(0.00?sec)??
  • ??
  • CREATE?TABLE?IF?NOT?EXISTS?`alluser`?(??
  • ????`id`?int(11)?NOT?NULL?AUTO_INCREMENT,??
  • ????`name`?varchar(50)?DEFAULT?NULL,??
  • ????`sex`?int(1)?NOT?NULL?DEFAULT?'0',??
  • ????INDEX(id)??
  • ??)?TYPE=MERGE?UNION=(user1,user2)?INSERT_METHOD=LAST?AUTO_INCREMENT=1?;??
  • Query?OK,?0?rows?affected,?1?warning?(0.00?sec)??
  • ??
  • mysql>?select?id,name,sex?from?alluser;??
  • +----+--------+-----+??
  • |?id?|?name???|?sex?|??
  • +----+--------+-----+??
  • |??1?|?張映?|???0?|??
  • |??1?|?tank???|???1?|??
  • +----+--------+-----+??
  • 2?rows?in?set?(0.00?sec)??
  • ??
  • mysql>?INSERT?INTO?`alluser`?(`name`,?`sex`)?VALUES('tank2',?0);??
  • Query?OK,?1?row?affected?(0.00?sec)??
  • ??
  • mysql>?select?id,name,sex?from?user2??
  • ?->?;??
  • +----+-------+-----+??
  • |?id?|?name??|?sex?|??
  • +----+-------+-----+??
  • |??1?|?tank??|???1?|??
  • |??2?|?tank2?|???0?|??
  • +----+-------+-----+??
  • 2?rows?in?set?(0.00?sec)??
  • 從上面的操作中,我不知道你有沒有發現點什么?假如我有一張用戶表user,有50W條數據,現在要拆成二張表user1和user2,每張表25W條數據,

    INSERT INTO user1(user1.id,user1.name,user1.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id <= 250000

    INSERT INTO user2(user2.id,user2.name,user2.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id > 250000

    這樣我就成功的將一張user表,分成了二個表,這個時候有一個問題,代碼中的sql語 句怎么辦,以前是一張表,現在變成二張表了,代碼改動很大,這樣給程序員帶來了很大的工作量,有沒有好的辦法解決這一點呢?辦法是把以前的user表備份 一下,然后刪除掉,上面的操作中我建立了一個alluser表,只把這個alluser表的表名改成user就行了。但是,不是所有的mysql操作都能 用的

    a,如果你使用 alter table 來把 merge 表變為其它表類型,到底層表的映射就被丟失了。取而代之的,來自底層 myisam 表的行被復制到已更換的表中,該表隨后被指定新類型。

    b,網上看到一些說replace不起作用,我試了一下可以起作用的。暈一個先

    Java代碼??
  • mysql>?UPDATE?alluser?SET?sex=REPLACE(sex,?0,?1)?where?id=2;????
  • Query?OK,?1?row?affected?(0.00?sec)????
  • ?Rows?matched:?1??Changed:?1??Warnings:?0????
  • ?????
  • ?mysql>?select?*?from?alluser;????
  • ?+----+--------+-----+????
  • ?|?id?|?name???|?sex?|????
  • ?+----+--------+-----+????
  • ?|??1?|?張映?|???0?|????
  • ?|??1?|?tank???|???1?|????
  • ?|??2?|?tank2??|???1?|????
  • ?+----+--------+-----+????
  • ?3?rows?in?set?(0.00?sec)????
  • ?

    c,一個 merge 表不能在整個表上維持 unique 約束。當你執行一個 insert,數據進入第一個或者最后一個 myisam 表(取決于 insert_method 選項的值)。mysql 確保唯一鍵值在那個 myisam 表里保持唯一,但不是跨集合里所有的表。

    d,當你創建一個 merge 表之時,沒有檢查去確保底層表的存在以及有相同的機構。當 merge 表被使用之時,mysql 檢查每個被映射的表的記錄長度是否相等,但這并不十分可靠。如果你從不相似的 myisam 表創建一個 merge 表,你非常有可能撞見奇怪的問題。

    好困睡覺了,c和d在網上看到的,沒有測試,大家試一下吧。

    優點:擴展性好,并且程序代碼改動的不是很大

    缺點:這種方法的效果比第二種要差一點

    三,總結一下

    上面提到的三種方法,我實際做過二種,第一種和第二種。第三種沒有做過,所以說的細一 點。哈哈。做什么事都有一個度,超過個度就過變得很差,不能一味的做數據庫服務器集群,硬件是要花錢買的,也不要一味的分表,分出來1000 表,mysql的存儲歸根到底還以文件的形勢存在硬盤上面,一張表對應三個文件,1000個分表就是對應3000個文件,這樣檢索起來也會變的很慢?。我的 建議是

    方法1和方法2結合的方式來進行分表

    方法1和方法3結合的方式來進行分表

    我的二個建議適合不同的情況,根據個人情況而定,我覺得會有很多人選擇方法1和方法3結合的方式

    ?

    分庫分表產生的問題,及注意事項
    1. 分庫分表維度的問題
    假如用戶購買了商品,需要將交易記錄保存取來,如果按照用戶的緯度分表,則每個用戶的交易記錄都保存在同一表中,所以很快很方便的查找到某用戶的購買情況,但是某商品被購買的情況則很有可能分布在多張表中,查找起來比較麻煩。反之,按照商品維度分表,可以很方便的查找到此商品的購買情況,但要查找到買人的交易記錄比較麻煩。?
    所以常見的解決方式有:
    ???? a.通過掃表的方式解決,此方法基本不可能,效率太低了。
    ???? b.記錄兩份數據,一份按照用戶緯度分表,一份按照商品維度分表。
    ???? c.通過搜索引擎解決,但如果實時性要求很高,又得關系到實時搜索。
    2. 聯合查詢的問題
    聯合查詢基本不可能,因為關聯的表有可能不在同一數據庫中。?
    3.?? 避免跨庫事務
    避免在一個事務中修改db0中的表的時候同時修改db1中的表,一個是操作起來更復雜,效率也會有一定影響。
    4.?? 盡量把同一組數據放到同一DB服務器上
    例如將賣家a的商品和交易信息都放到db0中,當db1掛了的時候,賣家a相關的東西可以正常使用。也就是說避免數據庫中的數據依賴另一數據庫中的數據。


    總結

    以上是生活随笔為你收集整理的mysql 分库分表的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 成人午夜在线 | 91在线观看视频 | 免费观看在线播放 | 日韩欧美中文字幕在线播放 | 免费公开在线视频 | 日本后进式猛烈xx00动态图 | 爱涩av| 亚洲精品乱| 天美视频在线观看 | 亚洲综合网在线 | 中文字幕无线精品亚洲乱码一区 | 狠狠干香蕉 | 欧美午夜激情影院 | 天天躁狠狠躁狠狠躁夜夜躁68 | 一本一道久久 | 日韩色区| 色婷婷久久综合 | xxx在线播放 | 久久青| 北条麻妃一区二区三区四区五区 | 黄色免费毛片 | 日韩成人av免费在线观看 | 精品国产美女 | 91视色 | 成人午夜激情影院 | 人人干人人干 | 午夜网址 | 爱就操 | 国产精品27p | 网站黄色在线观看 | 好色艳妇小说 | www日本com| 国产精品视频在线播放 | 手机看片福利在线 | 永久免费精品 | 日韩精品tv | 日韩专区在线 | 草草视频在线播放 | 国产一区二区三区www | 中文在线а√在线 | 亚洲精品热 | 色啪网站 | 97精品在线 | 国产亚洲二区 | 澳门三级 | 光棍影院手机版在线观看免费 | 久久av一区 | 亚洲综合天堂 | 久久只有这里有精品 | 黄色应用在线观看 | 2021亚洲天堂| 丰满少妇理论片 | 影视av | 尤物视频最新网址 | 黄色小说网站在线观看 | 亚洲精品一区二区三区中文字幕 | 六月丁香久久 | 亚洲乱码av | 日韩脚交footjobhd | 在线电影一区 | www成人免费| 黄色三级免费观看 | 国产激情啪啪 | 亚洲自拍偷拍精品视频 | 中文字幕无码精品亚洲 | 日本亚洲最大的色成网站www | 亚洲激情在线视频 | 午夜在线免费观看 | 91刺激| 亚洲精品一级 | 操色网 | www亚洲色图 | 黄瓜视频污在线观看 | 去毛片 | 亚洲精品国产精品乱码在线观看 | 在线视频观看国产 | 日韩理论在线观看 | 欧美高清精品一区二区 | 91福利在线视频 | 久久国产柳州莫菁门 | 国产97色在线 | 国产 | 97超碰免费在线 | 国产91高清 | 九九九在线视频 | 日韩精品一区二区三区中文字幕 | 国产高清露脸 | www.成人国产 | 精品国产1区 | 中文字幕亚洲色图 | 欧美成人一区二区三区 | 亚洲免费一级片 | 制服丝袜av在线 | 国产综合在线观看视频 | 日本涩涩网 | 欧美日韩中文字幕在线观看 | 日本高清视频一区二区 | 精品动漫3d一区二区三区免费版 | 国产精品theporn动漫 | 女人做爰全过程免费观看美女 |