• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            We do not always find visible happiness in proportion to visible virtue

            夢(mèng)幻白樺林

            SHARE

              C++博客 :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
              14 Posts :: 58 Stories :: 62 Comments :: 0 Trackbacks

            公告

            常用鏈接

            留言簿(5)

            搜索

            •  

            最新隨筆

            最新評(píng)論

            閱讀排行榜

            一、概述
             
            分表是個(gè)目前算是比較炒的比較流行的概念,特別是在大負(fù)載的情況下,分表是一個(gè)良好分散數(shù)據(jù)庫(kù)壓力的好方法。
             
            首先要了解為什么要分表,分表的好處是什么。我們先來(lái)大概了解以下一個(gè)數(shù)據(jù)庫(kù)執(zhí)行SQL的過(guò)程:
            接收到SQL --> 放入SQL執(zhí)行隊(duì)列 --> 使用分析器分解SQL --> 按照分析結(jié)果進(jìn)行數(shù)據(jù)的提取或者修改 --> 返回處理結(jié)果
             
            當(dāng)然,這個(gè)流程圖不一定正確,這只是我自己主觀意識(shí)上這么我認(rèn)為。那么這個(gè)處理過(guò)程當(dāng)中,最容易出現(xiàn)問(wèn)題的是什么?就是說(shuō),如果前一個(gè)SQL沒(méi) 有執(zhí)行完畢的話,后面的SQL是不會(huì)執(zhí)行的,因?yàn)闉榱吮WC數(shù)據(jù)的完整性,必須對(duì)數(shù)據(jù)表文件進(jìn)行鎖定,包括共享鎖和獨(dú)享鎖兩種鎖定。共享鎖是在鎖定的期間, 其它線程也可以訪問(wèn)這個(gè)數(shù)據(jù)文件,但是不允許修改操作,相應(yīng)的,獨(dú)享鎖就是整個(gè)文件就是歸一個(gè)線程所有,其它線程無(wú)法訪問(wèn)這個(gè)數(shù)據(jù)文件。一般MySQL中 最快的存儲(chǔ)引擎MyISAM,它是基于表鎖定的,就是說(shuō)如果一鎖定的話,那么整個(gè)數(shù)據(jù)文件外部都無(wú)法訪問(wèn),必須等前一個(gè)操作完成后,才能接收下一個(gè)操作, 那么在這個(gè)前一個(gè)操作沒(méi)有執(zhí)行完成,后一個(gè)操作等待在隊(duì)列里無(wú)法執(zhí)行的情況叫做阻塞,一般我們通俗意義上叫做“鎖表”。
             
            鎖表直接導(dǎo)致的后果是什么?就是大量的SQL無(wú)法立即執(zhí)行,必須等隊(duì)列前面的SQL全部執(zhí)行完畢才能繼續(xù)執(zhí)行。這個(gè)無(wú)法執(zhí)行的SQL就會(huì)導(dǎo)致沒(méi)有結(jié)果,或者延遲嚴(yán)重,影響用戶體驗(yàn)。
             
            特別是對(duì)于一些使用比較頻繁的表,比如SNS系統(tǒng)中的用戶信息表、論壇系統(tǒng)中的帖子表等等,都是訪問(wèn)量大很大的表,為了保證數(shù)據(jù)的快速提取返回給用戶,必須使用一些處理方式來(lái)解決這個(gè)問(wèn)題,這個(gè)就是我今天要聊到的分表技術(shù)。
             
             
            分表技術(shù)顧名思義,就是把若干個(gè)存儲(chǔ)相同類型數(shù)據(jù)的表分成幾個(gè)表分表存儲(chǔ),在提取數(shù)據(jù)的時(shí)候,不同的用戶訪問(wèn)不同的表,互不沖突,減少鎖表的幾 率。比如,目前保存用戶分表有兩個(gè)表,一個(gè)是user_1表,還有一個(gè)是 user_2 表,兩個(gè)表保存了不同的用戶信息,user_1 保存了前10萬(wàn)的用戶信息,user_2保存了后10萬(wàn)名用戶的信息,現(xiàn)在如果同時(shí)查詢用戶 heiyeluren1 和 heiyeluren2 這個(gè)兩個(gè)用戶,那么就是分表從不同的表提取出來(lái),減少鎖表的可能。
             
             
            我下面要講述的兩種分表方法我自己都沒(méi)有實(shí)驗(yàn)過(guò),不保證準(zhǔn)確能用,只是提供一個(gè)設(shè)計(jì)思路。下面關(guān)于分表的例子我假設(shè)是在一個(gè)貼吧系統(tǒng)的基礎(chǔ)上來(lái)進(jìn)行處理和構(gòu)建的。(如果沒(méi)有用過(guò)貼吧的用戶趕緊Google一下)
             
             
             
            二、基于基礎(chǔ)表的分表處理
             
            這個(gè)基于基礎(chǔ)表的分表處理方式大致的思想就是:一個(gè)主要表,保存了所有的基本信息,如果某個(gè)項(xiàng)目需要找到它所存儲(chǔ)的表,那么必須從這個(gè)基礎(chǔ)表中 查找出對(duì)應(yīng)的表名等項(xiàng)目,好直接訪問(wèn)這個(gè)表。如果覺得這個(gè)基礎(chǔ)表速度不夠快,可以完全把整個(gè)基礎(chǔ)表保存在緩存或者內(nèi)存中,方便有效的查詢。
             
            我們基于貼吧的情況,構(gòu)建假設(shè)如下的3張表:
             
            1. 貼吧版塊表: 保存貼吧中版塊的信息
            2. 貼吧主題表:保存貼吧中版塊中的主題信息,用于瀏覽
            3. 貼吧回復(fù)表:保存主題的原始內(nèi)容和回復(fù)內(nèi)容
             
             
            “貼吧版塊表”包含如下字段:
            版塊ID       board_id          int(10)
            版塊名稱    board_name      char(50)
            子表ID       table_id            smallint(5)
            產(chǎn)生時(shí)間    created             datetime
             
            “貼吧主題表”包含如下字段:
            主題ID          topic_id        int(10)
            主題名稱        topic_name     char(255)
            版塊ID          board_id          int(10)
            創(chuàng)建時(shí)間       created           datetime
             
            “貼吧回復(fù)表”的字段如下:
            回復(fù)ID        reply_id           int(10)
            回復(fù)內(nèi)容      reply_text        text
            主題ID        topic_id           int(10)
            版塊ID        board_id         int(10)
            創(chuàng)建時(shí)間      created            datetime
             
            那么上面保存了我們整個(gè)貼吧中的表結(jié)構(gòu)信息,三個(gè)表對(duì)應(yīng)的關(guān)系是:
             
            版塊 --> 多個(gè)主題
            主題 --> 多個(gè)回復(fù)
             
            那么就是說(shuō),表文件大小的關(guān)系是:
            版塊表文件 < 主題表文件 < 回復(fù)表文件
             
            所以基本可以確定需要對(duì)主題表和回復(fù)表進(jìn)行分表,已增加我們數(shù)據(jù)檢索查詢更改時(shí)候的速度和性能。
             
            看了上面的表結(jié)構(gòu),會(huì)明顯發(fā)現(xiàn),在“版塊表”中保存了一個(gè)"table_id"字段,這個(gè)字段就是用于保存一個(gè)版塊對(duì)應(yīng)的主題和回復(fù)都是分表保存在什么表里的。
             
            比如我們有一個(gè)叫做“PHP”的貼吧,board_id是1,子表ID也是1,那么這條記錄就是:
             
            board_id | board_name | table_id | created
            1 | PHP | 1 | 2007-01-19 00:30:12
             
            相應(yīng)的,如果我需要提取“PHP”吧里的所有主題,那么就必須按照表里保存的table_id來(lái)組合一個(gè)存儲(chǔ)了主題的表名稱,比如我們主題表的前綴是“topic_”,那么組合出來(lái)“PHP”吧對(duì)應(yīng)的主題表應(yīng)該是:“topic_1”,那么我們執(zhí)行:
             
            Select * FROM topic_1 Where board_id = 1 orDER BY topic_id DESC LIMIT 10
             
            這樣就能夠獲取這個(gè)主題下面回復(fù)列表,方便我們進(jìn)行查看,如果需要查看某個(gè)主題下面的回復(fù),我們可以繼續(xù)使用版塊表中保存的“table_id”來(lái)進(jìn)行查詢。比如我們回復(fù)表的前綴是“reply_”,那么就可以組合出“PHP”吧的ID為1的主題的回復(fù):
             
            Select * FROM reply_1 Where topic_id = 1 orDER BY reply_id DESC LIMIT 10
             
            這里,我們能夠清晰的看到,其實(shí)我們這里使用了基礎(chǔ)表,基礎(chǔ)表就是我們的版塊表。那么相應(yīng)的,肯定會(huì)說(shuō):基礎(chǔ)表的數(shù)據(jù)量大了以后如何保證它的速度和效率?
             
            當(dāng)然,我們就必須使得這個(gè)基礎(chǔ)表保持最好的速度和性能,比如,可以采用MySQL的內(nèi)存表來(lái)存儲(chǔ),或者保存在內(nèi)存當(dāng)中,比如Memcache之類的內(nèi)存緩存等等,可以按照實(shí)際情況來(lái)進(jìn)行調(diào)整。
             
            一般基于基礎(chǔ)表的分表機(jī)制在SNS、交友、論壇等Web2.0網(wǎng)站中是個(gè)比較不錯(cuò)的解決方案,在這些網(wǎng)站中,完全可以單獨(dú)使用一個(gè)表來(lái)來(lái)保存基本標(biāo)識(shí)和目標(biāo)表之間的關(guān)系。使用表保存對(duì)應(yīng)關(guān)系的好處是以后擴(kuò)展非常方便,只需要增加一個(gè)表記錄。
             
             
            優(yōu)勢(shì) 】增加刪除節(jié)點(diǎn)非常方便,為后期升級(jí)維護(hù)帶來(lái)很大便利
            劣勢(shì) 】需要增加表或者對(duì)某一個(gè)表進(jìn)行操作,還是無(wú)法離開數(shù)據(jù)庫(kù),會(huì)產(chǎn)生瓶頸
             
             
             
            三、基于 Hash 算法的分表處理
             
            我們知道Hash表就是通過(guò)某個(gè)特殊的Hash算法計(jì)算出的一個(gè)值,這個(gè)值必須是惟一的,并且能夠使用這個(gè)計(jì)算出來(lái)的值查找到需要的值,這個(gè)叫做哈希表。
             
            我們?cè)诜直砝锏膆ash算法跟這個(gè)思想類似:通過(guò)一個(gè)原始目標(biāo)的ID或者名稱通過(guò)一定的hash算法計(jì)算出數(shù)據(jù)存儲(chǔ)表的表名,然后訪問(wèn)相應(yīng)的表。
             
            繼續(xù)拿上面的貼吧來(lái)說(shuō),每個(gè)貼吧有版塊名稱和版塊ID,那么這兩項(xiàng)值是固定的,并且是惟一的,那么我們就可以考慮通過(guò)對(duì)這兩項(xiàng)值中的一項(xiàng)進(jìn)行一些運(yùn)算得出一個(gè)目標(biāo)表的名稱。
             
            現(xiàn)在假如我們針對(duì)我們這個(gè)貼吧系統(tǒng),假設(shè)系統(tǒng)最大允許1億條數(shù)據(jù),考慮每個(gè)表保存100萬(wàn)條記錄,那么整個(gè)系統(tǒng)就不超過(guò)100個(gè)表就能夠容納。按照這個(gè)標(biāo)準(zhǔn),我們假設(shè)在貼吧的版塊ID上進(jìn)行hash,獲得一個(gè)key值,這個(gè)值就是我們的表名,然后訪問(wèn)相應(yīng)的表。
             
            我們構(gòu)造一個(gè)簡(jiǎn)單的hash算法:
             
            function get_hash($id){
                 $str = bin2hex($id);
                 $hash = substr($str, 0, 4);
                 if (strlen($hash)<4){
                     $hash = str_pad($hash, 4, "0");
                 }
                 return $hash;
            }
             
            算法大致就是傳入一個(gè)版塊ID值,然后函數(shù)返回一個(gè)4位的字符串,如果字符串長(zhǎng)度不夠,使用0進(jìn)行補(bǔ)全。
             
            比如:get_hash(1),輸出的結(jié)果是“3100”,輸入:get_hash(23819),得到的結(jié)果是:3233,那么我們經(jīng)過(guò)簡(jiǎn)單的跟表前綴組合,就能夠訪問(wèn)這個(gè)表了。那么我們需要訪問(wèn)ID為1的內(nèi)容時(shí)候哦,組合的表將是:topic_3100、reply_3100,那么就可以直接對(duì)目標(biāo)表進(jìn)行訪問(wèn)了。
             
            當(dāng)然,使用hash算法后,有部分?jǐn)?shù)據(jù)是可能在同一個(gè)表的,這一點(diǎn)跟hash表不同,hash表是盡量解決沖突,我們這里不需要,當(dāng)然同樣需要預(yù)測(cè)和分析表數(shù)據(jù)可能保存的表名。
             
             
            如果需要存儲(chǔ)的數(shù)據(jù)更多,同樣的,可以對(duì)版塊的名字進(jìn)行hash操作,比如也是上面的二進(jìn)制轉(zhuǎn)換成十六進(jìn)制,因?yàn)闈h字比數(shù)字和字母要多很多,那么重復(fù)幾率更小,但是可能組合成的表就更多了,相應(yīng)就必須考慮一些其它的問(wèn)題。
             
            歸根結(jié)底,使用hash方式的話必須選擇一個(gè)好的hash算法,才能生成更多的表,然數(shù)據(jù)查詢的更迅速。
             
             
            優(yōu)點(diǎn)hash算法直接得出目標(biāo)表名稱,效率很高 】通過(guò)
            劣勢(shì) 】擴(kuò)展性比較差,選擇了一個(gè)hash算法,定義了多少數(shù)據(jù)量,以后只能在這個(gè)數(shù)據(jù)量上跑,不能超過(guò)過(guò)這個(gè)數(shù)據(jù)量,可擴(kuò)展性稍差
             
             
             
            四、其它問(wèn)題
             
            1. 搜索問(wèn)題
            現(xiàn)在我們已經(jīng)進(jìn)行分表了,那么就無(wú)法直接對(duì)表進(jìn)行搜索,因?yàn)槟銦o(wú)法對(duì)可能系統(tǒng)中已經(jīng)存在的幾十或者幾百個(gè)表進(jìn)行檢索,所以搜索必須借助第三方的組件來(lái)進(jìn)行,比如Lucene作為站內(nèi)搜索引擎是個(gè)不錯(cuò)的選擇。
             
            2. 表文件問(wèn)題
            我們知道MySQL的MyISAM引擎每個(gè)表都會(huì)生成三個(gè)文件,*.frm、*.MYD、*.MYI 三個(gè)文件,分表用來(lái)保存表結(jié)構(gòu)、表數(shù)據(jù)和表索引。Linux下面每個(gè)目錄下的文件數(shù)量最好不要超過(guò)1000個(gè),不然檢索數(shù)據(jù)將更慢,那么每個(gè)表都會(huì)生成三 個(gè)文件,相應(yīng)的如果分表超過(guò)300個(gè)表,那么將檢索非常慢,所以這時(shí)候就必須再進(jìn)行分,比如在進(jìn)行數(shù)據(jù)庫(kù)的分離。
             
            使用基礎(chǔ)表,我們可以新增加一個(gè)字段,用來(lái)保存這個(gè)表保存在什么數(shù)據(jù)。使用Hash的方式,我們必須截取hash值中第幾位來(lái)作為數(shù)據(jù)庫(kù)的名字。這樣,完好的解決這個(gè)問(wèn)題。
             
             
            五、總結(jié)
             
            在大負(fù)載應(yīng)用當(dāng)中,數(shù)據(jù)庫(kù)一直是個(gè)很重要的瓶頸,必須要突破,本文講解了兩種分表的方式,希望對(duì)很多人能夠有啟發(fā)的作用。當(dāng)然,本文代碼和設(shè)想沒(méi)有經(jīng)過(guò)任何代碼測(cè)試,所以無(wú)法保證設(shè)計(jì)的完全準(zhǔn)確實(shí)用,具體還是需要讀者在使用過(guò)程當(dāng)中認(rèn)真分析實(shí)施。
             

            posted on 2007-09-18 09:51 colys 閱讀(566) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C#.NetoracleSqlServer

            精品久久久久久中文字幕人妻最新| 久久这里只有精品久久| 亚洲精品国产成人99久久| 久久久一本精品99久久精品88| 99久久免费国产精品特黄| 久久久精品视频免费观看| 国产成人久久精品麻豆一区| 99国内精品久久久久久久| 夜夜亚洲天天久久| 久久精品18| 狠狠色丁香久久婷婷综合蜜芽五月| 四虎影视久久久免费| 香蕉99久久国产综合精品宅男自 | 亚洲欧美日韩久久精品| 久久久中文字幕日本| 亚洲精品NV久久久久久久久久 | 久久不射电影网| 青青青国产成人久久111网站| 国产精品久久久久aaaa| 九九99精品久久久久久| 久久久无码精品亚洲日韩软件| 青青热久久国产久精品| 亚洲色大成网站www久久九| 国产亚洲精久久久久久无码| 国产成人久久精品二区三区| 亚洲日韩欧美一区久久久久我 | 久久国产视屏| 亚洲AV无一区二区三区久久| 久久福利青草精品资源站| 久久久久久青草大香综合精品| 久久精品国产亚洲AV忘忧草18| 国产精品久久久久无码av| 久久久久亚洲AV综合波多野结衣 | 人人狠狠综合久久亚洲88| 久久亚洲精品无码播放| 亚洲AV无码1区2区久久| 久久国产影院| 久久综合给合久久国产免费| 亚洲国产成人久久一区久久| 久久久国产精品福利免费| 精品综合久久久久久98|