1.數(shù)據(jù)存儲(chǔ)
1) MySQL 索引使用的注意事項(xiàng)
(1)。索引不會(huì)包含有NULL的列
只要列中包含有NULL值,都將不會(huì)被包含在索引中,復(fù)合索引中只要有一列含有NULL值,那么這一列對(duì)于此符合索引就是無(wú)效的。
(2)。使用短索引
對(duì)串列進(jìn)行索引,如果可以就應(yīng)該指定一個(gè)前綴長(zhǎng)度。例如,如果有一個(gè)char(255)的列,如果在前10個(gè)或20個(gè)字符內(nèi),多數(shù)值是唯一的,那么就不要對(duì)整個(gè)列進(jìn)行索引。短索引不僅可以提高查詢速度而且可以節(jié)省磁盤空間和I/O操作。
(3)。索引列排序
mysql查詢只使用一個(gè)索引,因此如果where子句中已經(jīng)使用了索引的話,那么order by中的列是不會(huì)使用索引的。因此數(shù)據(jù)庫(kù)默認(rèn)排序可以符合要求的情況下不要使用排序操作,盡量不要包含多個(gè)列的排序,如果需要最好給這些列建復(fù)合索引。
(4).like語(yǔ)句操作
一般情況下不鼓勵(lì)使用like操作,如果非使用不可,注意正確的使用方式。like ‘%aaa%’不會(huì)使用索引,而like ‘a(chǎn)aa%’可以使用索引。
(5)。不要在列上進(jìn)行運(yùn)算
(6)。不使用NOT IN 、《》、!=操作,但《,《=,=,》,》=,BETWEEN,IN是可以用到索引的
(7)。索引要建立在經(jīng)常進(jìn)行select操作的字段上。
這是因?yàn)?,如果這些列很少用到,那么有無(wú)索引并不能明顯改變查詢速度。相反,由于增加了索引,反而降低了系統(tǒng)的維護(hù)速度和增大了空間需求。
(8)。索引要建立在值比較唯一的字段上。
(9)。對(duì)于那些定義為text、image和bit數(shù)據(jù)類型的列不應(yīng)該增加索引。因?yàn)檫@些列的數(shù)據(jù)量要么相當(dāng)大,要么取值很少。
(10)。在where和join中出現(xiàn)的列需要建立索引。
(11).where的查詢條件里有不等號(hào)(where column != …),mysql將無(wú)法使用索引。
(12)。如果where字句的查詢條件里使用了函數(shù)(如:where DAY(column)=…),mysql將無(wú)法使用索引。
(13)。在join操作中(需要從多個(gè)數(shù)據(jù)表提取數(shù)據(jù)時(shí)),mysql只有在主鍵和外鍵的數(shù)據(jù)類型相同時(shí)才能使用索引,否則及時(shí)建立了索引也不會(huì)使用。
2) 說(shuō)說(shuō)反模式設(shè)計(jì)
簡(jiǎn)單的來(lái)說(shuō),反模式是指在對(duì)經(jīng)常面對(duì)的問(wèn)題經(jīng)常使用的低效,不良,或者有待優(yōu)化的設(shè)計(jì)模式/方法。甚至,反模式也可以是一種錯(cuò)誤的開發(fā)思想/理念。在這里我舉一個(gè)最簡(jiǎn)單的例子:在面向?qū)ο笤O(shè)計(jì)/編程中,有一條很重要的原則, 單一責(zé)任原則(Single responsibility principle)。其中心思想就是對(duì)于一個(gè)模塊,或者一個(gè)類來(lái)說(shuō),這個(gè)模塊或者這個(gè)類應(yīng)該只對(duì)系統(tǒng)/軟件的一個(gè)功能負(fù)責(zé),而且該責(zé)任應(yīng)該被該類完全封裝起來(lái)。當(dāng)開發(fā)人員需要修改系統(tǒng)的某個(gè)功能,這個(gè)模塊/類是最主要的修改地方。相對(duì)應(yīng)的一個(gè)反模式就是上帝類(God Class),通常來(lái)說(shuō),這個(gè)類里面控制了很多其他的類,同時(shí)也依賴其他很多類。整個(gè)類不光負(fù)責(zé)自己的主要單一功能,而且還負(fù)責(zé)了其他很多功能,包括一些輔助功能。很多維護(hù)老程序的開發(fā)人員們可能都遇過(guò)這種類,一個(gè)類里有幾千行的代碼,有很多功能,但是責(zé)任不明確單一。單元測(cè)試程序也變復(fù)雜無(wú)比。維護(hù)/修改這個(gè)類的時(shí)間要遠(yuǎn)遠(yuǎn)超出其他類的時(shí)間。很多時(shí)候,形成這種情況并不是開發(fā)人員故意的。很多情況下主要是由于隨著系統(tǒng)的年限,需求的變化,項(xiàng)目的資源壓力,項(xiàng)目組人員流動(dòng),系統(tǒng)結(jié)構(gòu)的變化而導(dǎo)致某些原先小型的,符合單一原則類慢慢的變的臃腫起來(lái)。最后當(dāng)這個(gè)類變成了維護(hù)的噩夢(mèng)(特別是原先熟悉的開發(fā)人員離職后),重構(gòu)該類就變成了一個(gè)不容易的工程。
3) 說(shuō)說(shuō)分庫(kù)與分表設(shè)計(jì)
垂直分表在日常開發(fā)和設(shè)計(jì)中比較常見(jiàn),通俗的說(shuō)法叫做“大表拆小表”,拆分是基于關(guān)系型數(shù)據(jù)庫(kù)中的“列”(字段)進(jìn)行的。通常情況,某個(gè)表中的字段比較多,可以新建立一張“擴(kuò)展表”,將不經(jīng)常使用或者長(zhǎng)度較大的字段拆分出去放到“擴(kuò)展表”中。在字段很多的情況下,拆分開確實(shí)更便于開發(fā)和維護(hù)(筆者曾見(jiàn)過(guò)某個(gè)遺留系統(tǒng)中,一個(gè)大表中包含100多列的)。某種意義上也能避免“跨頁(yè)”的問(wèn)題(MySQL、MSSQL底層都是通過(guò)“數(shù)據(jù)頁(yè)”來(lái)存儲(chǔ)的,“跨頁(yè)”問(wèn)題可能會(huì)造成額外的性能開銷,拆分字段的操作建議在數(shù)據(jù)庫(kù)設(shè)計(jì)階段就做好。如果是在發(fā)展過(guò)程中拆分,則需要改寫以前的查詢語(yǔ)句,會(huì)額外帶來(lái)一定的成本和風(fēng)險(xiǎn),建議謹(jǐn)慎。
垂直分庫(kù)在“微服務(wù)”盛行的今天已經(jīng)非常普及了?;镜乃悸肪褪前凑諛I(yè)務(wù)模塊來(lái)劃分出不同的數(shù)據(jù)庫(kù),而不是像早期一樣將所有的數(shù)據(jù)表都放到同一個(gè)數(shù)據(jù)庫(kù)中。系統(tǒng)層面的“服務(wù)化”拆分操作,能夠解決業(yè)務(wù)系統(tǒng)層面的耦合和性能瓶頸,有利于系統(tǒng)的擴(kuò)展維護(hù)。而數(shù)據(jù)庫(kù)層面的拆分,道理也是相通的。與服務(wù)的“治理”和“降級(jí)”機(jī)制類似,我們也能對(duì)不同業(yè)務(wù)類型的數(shù)據(jù)進(jìn)行“分級(jí)”管理、維護(hù)、監(jiān)控、擴(kuò)展等。
眾所周知,數(shù)據(jù)庫(kù)往往最容易成為應(yīng)用系統(tǒng)的瓶頸,而數(shù)據(jù)庫(kù)本身屬于“有狀態(tài)”的,相對(duì)于Web和應(yīng)用服務(wù)器來(lái)講,是比較難實(shí)現(xiàn)“橫向擴(kuò)展”的。數(shù)據(jù)庫(kù)的連接資源比較寶貴且單機(jī)處理能力也有限,在高并發(fā)場(chǎng)景下,垂直分庫(kù)一定程度上能夠突破IO、連接數(shù)及單機(jī)硬件資源的瓶頸,是大型分布式系統(tǒng)中優(yōu)化數(shù)據(jù)庫(kù)架構(gòu)的重要手段。
然后,很多人并沒(méi)有從根本上搞清楚為什么要拆分,也沒(méi)有掌握拆分的原則和技巧,只是一味的模仿大廠的做法。導(dǎo)致拆分后遇到很多問(wèn)題(例如:跨庫(kù)join,分布式事務(wù)等)。
水平分表也稱為橫向分表,比較容易理解,就是將表中不同的數(shù)據(jù)行按照一定規(guī)律分布到不同的數(shù)據(jù)庫(kù)表中(這些表保存在同一個(gè)數(shù)據(jù)庫(kù)中),這樣來(lái)降低單表數(shù)據(jù)量,優(yōu)化查詢性能。最常見(jiàn)的方式就是通過(guò)主鍵或者時(shí)間等字段進(jìn)行Hash和取模后拆分。水平分表,能夠降低單表的數(shù)據(jù)量,一定程度上可以緩解查詢性能瓶頸。但本質(zhì)上這些表還保存在同一個(gè)庫(kù)中,所以庫(kù)級(jí)別還是會(huì)有IO瓶頸。所以,一般不建議采用這種做法。
水平分庫(kù)分表與上面講到的水平分表的思想相同,唯一不同的就是將這些拆分出來(lái)的表保存在不同的數(shù)據(jù)中。這也是很多大型互聯(lián)網(wǎng)公司所選擇的做法。某種意義上來(lái)講,有些系統(tǒng)中使用的“冷熱數(shù)據(jù)分離”(將一些使用較少的歷史數(shù)據(jù)遷移到其他的數(shù)據(jù)庫(kù)中。而在業(yè)務(wù)功能上,通常默認(rèn)只提供熱點(diǎn)數(shù)據(jù)的查詢),也是類似的實(shí)踐。在高并發(fā)和海量數(shù)據(jù)的場(chǎng)景下,分庫(kù)分表能夠有效緩解單機(jī)和單庫(kù)的性能瓶頸和壓力,突破IO、連接數(shù)、硬件資源的瓶頸。當(dāng)然,投入的硬件成本也會(huì)更高。同時(shí),這也會(huì)帶來(lái)一些復(fù)雜的技術(shù)問(wèn)題和挑戰(zhàn)(例如:跨分片的復(fù)雜查詢,跨分片事務(wù)等)。
4) 分庫(kù)與分表帶來(lái)的分布式困境與應(yīng)對(duì)之策
數(shù)據(jù)遷移與擴(kuò)容問(wèn)題
前面介紹到水平分表策略歸納總結(jié)為隨機(jī)分表和連續(xù)分表兩種情況。連續(xù)分表有可能存在數(shù)據(jù)熱點(diǎn)的問(wèn)題,有些表可能會(huì)被頻繁地查詢從而造成較大壓力,熱數(shù)據(jù)的表就成為了整個(gè)庫(kù)的瓶頸,而有些表可能存的是歷史數(shù)據(jù),很少需要被查詢到。連續(xù)分表的另外一個(gè)好處在于比較容易,不需要考慮遷移舊的數(shù)據(jù),只需要添加分表就可以自動(dòng)擴(kuò)容。隨機(jī)分表的數(shù)據(jù)相對(duì)比較均勻,不容易出現(xiàn)熱點(diǎn)和并發(fā)訪問(wèn)的瓶頸。但是,分表擴(kuò)展需要遷移舊的數(shù)據(jù)。
針對(duì)于水平分表的設(shè)計(jì)至關(guān)重要,需要評(píng)估中短期內(nèi)業(yè)務(wù)的增長(zhǎng)速度,對(duì)當(dāng)前的數(shù)據(jù)量進(jìn)行容量規(guī)劃,綜合成本因素,推算出大概需要多少分片。對(duì)于數(shù)據(jù)遷移的問(wèn)題,一般做法是通過(guò)程序先讀出數(shù)據(jù),然后按照指定的分表策略再將數(shù)據(jù)寫入到各個(gè)分表中。
表關(guān)聯(lián)問(wèn)題
在單庫(kù)單表的情況下,聯(lián)合查詢是非常容易的。但是,隨著分庫(kù)與分表的演變,聯(lián)合查詢就遇到跨庫(kù)關(guān)聯(lián)和跨表關(guān)系問(wèn)題。在設(shè)計(jì)之初就應(yīng)該盡量避免聯(lián)合查詢,可以通過(guò)程序中進(jìn)行拼裝,或者通過(guò)反范式化設(shè)計(jì)進(jìn)行規(guī)避。
分頁(yè)與排序問(wèn)題
一般情況下,列表分頁(yè)時(shí)需要按照指定字段進(jìn)行排序。在單庫(kù)單表的情況下,分頁(yè)和排序也是非常容易的。但是,隨著分庫(kù)與分表的演變,也會(huì)遇到跨庫(kù)排序和跨表排序問(wèn)題。為了最終結(jié)果的準(zhǔn)確性,需要在不同的分表中將數(shù)據(jù)進(jìn)行排序并返回,并將不同分表返回的結(jié)果集進(jìn)行匯總和再次排序,最后再返回給用戶。
分布式事務(wù)問(wèn)題
隨著分庫(kù)與分表的演變,一定會(huì)遇到分布式事務(wù)問(wèn)題,那么如何保證數(shù)據(jù)的一致性就成為一個(gè)必須面對(duì)的問(wèn)題。目前,分布式事務(wù)并沒(méi)有很好的解決方案,難以滿足數(shù)據(jù)強(qiáng)一致性,一般情況下,使存儲(chǔ)數(shù)據(jù)盡可能達(dá)到用戶一致,保證系統(tǒng)經(jīng)過(guò)一段較短的時(shí)間的自我恢復(fù)和修正,數(shù)據(jù)最終達(dá)到一致。
分布式全局唯一ID
在單庫(kù)單表的情況下,直接使用數(shù)據(jù)庫(kù)自增特性來(lái)生成主鍵ID,這樣確實(shí)比較簡(jiǎn)單。在分庫(kù)分表的環(huán)境中,數(shù)據(jù)分布在不同的分表上,不能再借助數(shù)據(jù)庫(kù)自增長(zhǎng)特性。需要使用全局唯一 ID,例如 UUID、GUID等。關(guān)于如何選擇合適的全局唯一 ID,我會(huì)在后面的章節(jié)中進(jìn)行介紹。
摘抄自:http://blog.csdn.net/jiangpingjiangping/article/details/78069480
5) 說(shuō)說(shuō) SQL 優(yōu)化之道
(一)、一些常見(jiàn)的SQL實(shí)踐
(1)負(fù)向條件查詢不能使用索引
select from order where status!=0 and stauts!=1
not in/not exists都不是好習(xí)慣
可以優(yōu)化為in查詢:
select from order where status in(2,3)
(2)前導(dǎo)模糊查詢不能使用索引
select from order where desc like ‘%XX’
而非前導(dǎo)模糊查詢則可以:
select from order where desc like ‘XX%’
(3)數(shù)據(jù)區(qū)分度不大的字段不宜使用索引
select from user where sex=1
原因:性別只有男,女,每次過(guò)濾掉的數(shù)據(jù)很少,不宜使用索引。
經(jīng)驗(yàn)上,能過(guò)濾80%數(shù)據(jù)時(shí)就可以使用索引。對(duì)于訂單狀態(tài),如果狀態(tài)值很少,不宜使用索引,如果狀態(tài)值很多,能夠過(guò)濾大量數(shù)據(jù),則應(yīng)該建立索引。
(4)在屬性上進(jìn)行計(jì)算不能命中索引
select from order where YEAR(date) 《 = ‘2017’
即使date上建立了索引,也會(huì)全表掃描,可優(yōu)化為值計(jì)算:
select from order where date 《 = CURDATE()
或者:
select from order where date 《 = ‘2017-01-01’
(二)、并非周知的SQL實(shí)踐
(5)如果業(yè)務(wù)大部分是單條查詢,使用Hash索引性能更好,例如用戶中心
select from user where uid=? select from user where login_name=?
原因:B-Tree索引的時(shí)間復(fù)雜度是O(log(n));Hash索引的時(shí)間復(fù)雜度是O(1)
(6)允許為null的列,查詢有潛在大坑
單列索引不存null值,復(fù)合索引不存全為null的值,如果列允許為null,可能會(huì)得到“不符合預(yù)期”的結(jié)果集
select from user where name != ‘shenjian’
如果name允許為null,索引不存儲(chǔ)null值,結(jié)果集中不會(huì)包含這些記錄。
所以,請(qǐng)使用not null約束以及默認(rèn)值。
(7)復(fù)合索引最左前綴,并不是值SQL語(yǔ)句的where順序要和復(fù)合索引一致
用戶中心建立了(login_name, passwd)的復(fù)合索引:
select from user where login_name=? and passwd=?
select from user where passwd=? and login_name=?
都能夠命中索引
select from user where login_name=?
也能命中索引,滿足復(fù)合索引最左前綴
select from user where passwd=?
不能命中索引,不滿足復(fù)合索引最左前綴
(8)使用ENUM而不是字符串
ENUM保存的是TINYINT,別在枚舉中搞一些“中國(guó)”“北京”“技術(shù)部”這樣的字符串,字符串空間又大,效率又低。
(三)、小眾但有用的SQL實(shí)踐
(9)如果明確知道只有一條結(jié)果返回,limit 1能夠提高效率
select from user where login_name=?
可以優(yōu)化為:
select from user where login_name=? limit 1
原因:你知道只有一條結(jié)果,但數(shù)據(jù)庫(kù)并不知道,明確告訴它,讓它主動(dòng)停止游標(biāo)移動(dòng)
(10)把計(jì)算放到業(yè)務(wù)層而不是數(shù)據(jù)庫(kù)層,除了節(jié)省數(shù)據(jù)的CPU,還有意想不到的查詢緩存優(yōu)化效果
select from order where date 《 = CURDATE()
這不是一個(gè)好的SQL實(shí)踐,應(yīng)該優(yōu)化為:
$curDate = date(‘Y-m-d’);
$res = mysqlquery(
‘select from order where date 《 = $curDate’);
原因:
釋放了數(shù)據(jù)庫(kù)的CPU
多次調(diào)用,傳入的SQL相同,才可以利用查詢緩存
(11)強(qiáng)制類型轉(zhuǎn)換會(huì)全表掃描
select from user where phone=13800001234
你以為會(huì)命中phone索引么?大錯(cuò)特錯(cuò)了,這個(gè)語(yǔ)句究竟要怎么改?
末了,再加一條,不要使用select *(潛臺(tái)詞,文章的SQL都不合格 ==),只返回需要的列,能夠大大的節(jié)省數(shù)據(jù)傳輸量,與數(shù)據(jù)庫(kù)的內(nèi)存使用量喲。
6) MySQL 遇到的死鎖問(wèn)題
產(chǎn)生死鎖的四個(gè)必要條件:
(1) 互斥條件:一個(gè)資源每次只能被一個(gè)進(jìn)程使用。
(2) 請(qǐng)求與保持條件:一個(gè)進(jìn)程因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放。
(3) 不剝奪條件:進(jìn)程已獲得的資源,在末使用完之前,不能強(qiáng)行剝奪。
(4) 循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
這四個(gè)條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會(huì)發(fā)生死鎖。
下列方法有助于最大限度地降低死鎖:
(1)按同一順序訪問(wèn)對(duì)象。
(2)避免事務(wù)中的用戶交互。
(3)保持事務(wù)簡(jiǎn)短并在一個(gè)批處理中。
(4)使用低隔離級(jí)別。
(5)使用綁定連接。
7) 存儲(chǔ)引擎的 InnoDB 與 MyISAM
(1).InnoDB不支持FULLTEXT類型的索引。
(2).InnoDB 中不保存表的具體行數(shù),也就是說(shuō),執(zhí)行select count() from table時(shí),InnoDB要掃描一遍整個(gè)表來(lái)計(jì)算有多少行,但是MyISAM只要簡(jiǎn)單的讀出保存好的行數(shù)即可。注意的是,當(dāng)count()語(yǔ)句包含 where條件時(shí),兩種表的操作是一樣的。
(3)。對(duì)于AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中,可以和其他字段一起建立聯(lián)合索引。
(4).DELETE FROM table時(shí),InnoDB不會(huì)重新建立表,而是一行一行的刪除。
(5).LOAD TABLE FROM MASTER操作對(duì)InnoDB是不起作用的,解決方法是首先把InnoDB表改成MyISAM表,導(dǎo)入數(shù)據(jù)后再改成InnoDB表,但是對(duì)于使用的額外的InnoDB特性(例如外鍵)的表不適用。
另外,InnoDB表的行鎖也不是絕對(duì)的,假如在執(zhí)行一個(gè)SQL語(yǔ)句時(shí)MySQL不能確定要掃描的范圍,InnoDB表同樣會(huì)鎖全表,例如update table set num=1 where name like “%aaa%”
8) 數(shù)據(jù)庫(kù)索引的原理
數(shù)據(jù)庫(kù)索引,是數(shù)據(jù)庫(kù)管理系統(tǒng)中一個(gè)排序的數(shù)據(jù)結(jié)構(gòu),以協(xié)助快速查詢、更新數(shù)據(jù)庫(kù)表中數(shù)據(jù)。索引的實(shí)現(xiàn)通常使用B樹及其變種B+樹。
9) 為什么要用 B-tree
一般來(lái)說(shuō),索引本身也很大,不可能全部存儲(chǔ)在內(nèi)存中,因此索引往往以索引文件的形式存儲(chǔ)的磁盤上。這樣的話,索引查找過(guò)程中就要產(chǎn)生磁盤I/O消耗,相對(duì)于內(nèi)存存取,I/O存取的消耗要高幾個(gè)數(shù)量級(jí),所以評(píng)價(jià)一個(gè)數(shù)據(jù)結(jié)構(gòu)作為索引的優(yōu)劣最重要的指標(biāo)就是在查找過(guò)程中磁盤I/O操作次數(shù)的漸進(jìn)復(fù)雜度。換句話說(shuō),索引的結(jié)構(gòu)組織要盡量減少查找過(guò)程中磁盤I/O的存取次數(shù)。
10) 聚集索引與非聚集索引的區(qū)別
(1)。聚集索引一個(gè)表只能有一個(gè),而非聚集索引一個(gè)表可以存在多個(gè)
(2)。聚集索引存儲(chǔ)記錄是物理上連續(xù)存在,而非聚集索引是邏輯上的連續(xù),物理存儲(chǔ)并不連續(xù)
(3)。聚集索引:物理存儲(chǔ)按照索引排序;聚集索引是一種索引組織形式,索引的鍵值邏輯順序決定了表數(shù)據(jù)行的物理存儲(chǔ)順序
非聚集索引:物理存儲(chǔ)不按照索引排序;非聚集索引則就是普通索引了,僅僅只是對(duì)數(shù)據(jù)列創(chuàng)建相應(yīng)的索引,不影響整個(gè)表的物理存儲(chǔ)順序。
(4)。索引是通過(guò)二叉樹的數(shù)據(jù)結(jié)構(gòu)來(lái)描述的,我們可以這么理解聚簇索引:索引的葉節(jié)點(diǎn)就是數(shù)據(jù)節(jié)點(diǎn)。而非聚簇索引的葉節(jié)點(diǎn)仍然是索引節(jié)點(diǎn),只不過(guò)有一個(gè)指針指向?qū)?yīng)的數(shù)據(jù)塊。
11) limit 20000 加載很慢怎么解決
mysql的性能低是因?yàn)閿?shù)據(jù)庫(kù)要去掃描N+M條記錄,然后又要放棄之前N條記錄,開銷很大
解決思略:
(1)、前端加緩存,或者其他方式,減少落到庫(kù)的查詢操作,例如某些系統(tǒng)中數(shù)據(jù)在搜索引擎中有備份的,可以用es等進(jìn)行搜索
(2)、使用延遲關(guān)聯(lián),即先通用limit得到需要數(shù)據(jù)的索引字段,然后再通過(guò)原表和索引字段關(guān)聯(lián)獲得需要數(shù)據(jù)
select a.* from a,(select id from table_1 where is_deleted=‘N’ limit 100000,20) b where a.id = b.id
(3)、從業(yè)務(wù)上實(shí)現(xiàn),不分頁(yè)如此多,例如只能分頁(yè)前100頁(yè),后面的不允許再查了
(4)、不使用limit N,M,而是使用limit N,即將offset轉(zhuǎn)化為where條件。
12) 選擇合適的分布式主鍵方案
數(shù)據(jù)庫(kù)自增長(zhǎng)序列或字段
UUID
使用UUID to Int64的方法
Redis生成ID
Twitter的snowflake算法
利用zookeeper生成唯一ID
MongoDB的ObjectId
13) 選擇合適的數(shù)據(jù)存儲(chǔ)方案
關(guān)系型數(shù)據(jù)庫(kù) MySQL
MySQL 是一個(gè)最流行的關(guān)系型數(shù)據(jù)庫(kù),在互聯(lián)網(wǎng)產(chǎn)品中應(yīng)用比較廣泛。一般情況下,MySQL 數(shù)據(jù)庫(kù)是選擇的第一方案,基本上有 80% ~ 90% 的場(chǎng)景都是基于 MySQL 數(shù)據(jù)庫(kù)的。因?yàn)?,需要關(guān)系型數(shù)據(jù)庫(kù)進(jìn)行管理,此外,業(yè)務(wù)存在許多事務(wù)性的操作,需要保證事務(wù)的強(qiáng)一致性。同時(shí),可能還存在一些復(fù)雜的 SQL 的查詢。值得注意的是,前期盡量減少表的聯(lián)合查詢,便于后期數(shù)據(jù)量增大的情況下,做數(shù)據(jù)庫(kù)的分庫(kù)分表。
內(nèi)存數(shù)據(jù)庫(kù) Redis
隨著數(shù)據(jù)量的增長(zhǎng),MySQL 已經(jīng)滿足不了大型互聯(lián)網(wǎng)類應(yīng)用的需求。因此,Redis 基于內(nèi)存存儲(chǔ)數(shù)據(jù),可以極大的提高查詢性能,對(duì)產(chǎn)品在架構(gòu)上很好的補(bǔ)充。例如,為了提高服務(wù)端接口的訪問(wèn)速度,盡可能將讀頻率高的熱點(diǎn)數(shù)據(jù)存放在 Redis 中。這個(gè)是非常典型的以空間換時(shí)間的策略,使用更多的內(nèi)存換取 CPU 資源,通過(guò)增加系統(tǒng)的內(nèi)存消耗,來(lái)加快程序的運(yùn)行速度。
在某些場(chǎng)景下,可以充分的利用 Redis 的特性,大大提高效率。這些場(chǎng)景包括緩存,會(huì)話緩存,時(shí)效性,訪問(wèn)頻率,計(jì)數(shù)器,社交列表,記錄用戶判定信息,交集、并集和差集,熱門列表與排行榜,最新動(dòng)態(tài)等。
使用 Redis 做緩存的時(shí)候,需要考慮數(shù)據(jù)不一致與臟讀、緩存更新機(jī)制、緩存可用性、緩存服務(wù)降級(jí)、緩存穿透、緩存預(yù)熱等緩存使用問(wèn)題。
文檔數(shù)據(jù)庫(kù) MongoDB
MongoDB 是對(duì)傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)的補(bǔ)充,它非常適合高伸縮性的場(chǎng)景,它是可擴(kuò)展性的表結(jié)構(gòu)?;谶@點(diǎn),可以將預(yù)期范圍內(nèi),表結(jié)構(gòu)可能會(huì)不斷擴(kuò)展的 MySQL 表結(jié)構(gòu),通過(guò) MongoDB 來(lái)存儲(chǔ),這就可以保證表結(jié)構(gòu)的擴(kuò)展性。
此外,日志系統(tǒng)數(shù)據(jù)量特別大,如果用 MongoDB 數(shù)據(jù)庫(kù)存儲(chǔ)這些數(shù)據(jù),利用分片集群支持海量數(shù)據(jù),同時(shí)使用聚集分析和 MapReduce 的能力,是個(gè)很好的選擇。
MongoDB 還適合存儲(chǔ)大尺寸的數(shù)據(jù),GridFS 存儲(chǔ)方案就是基于 MongoDB 的分布式文件存儲(chǔ)系統(tǒng)。
列族數(shù)據(jù)庫(kù) HBase
HBase 適合海量數(shù)據(jù)的存儲(chǔ)與高性能實(shí)時(shí)查詢,它是運(yùn)行于 HDFS 文件系統(tǒng)之上,并且作為 MapReduce 分布式處理的目標(biāo)數(shù)據(jù)庫(kù),以支撐離線分析型應(yīng)用。在數(shù)據(jù)倉(cāng)庫(kù)、數(shù)據(jù)集市、商業(yè)智能等領(lǐng)域發(fā)揮了越來(lái)越多的作用,在數(shù)以千計(jì)的企業(yè)中支撐著大量的大數(shù)據(jù)分析場(chǎng)景的應(yīng)用。
全文搜索引擎 ElasticSearch
在一般情況下,關(guān)系型數(shù)據(jù)庫(kù)的模糊查詢,都是通過(guò) like 的方式進(jìn)行查詢。其中,like “value%” 可以使用索引,但是對(duì)于 like “%value%” 這樣的方式,執(zhí)行全表查詢,這在數(shù)據(jù)量小的表,不存在性能問(wèn)題,但是對(duì)于海量數(shù)據(jù),全表掃描是非??膳碌氖虑椤lasticSearch 作為一個(gè)建立在全文搜索引擎 Apache Lucene 基礎(chǔ)上的實(shí)時(shí)的分布式搜索和分析引擎,適用于處理實(shí)時(shí)搜索應(yīng)用場(chǎng)景。此外,使用 ElasticSearch 全文搜索引擎,還可以支持多詞條查詢、匹配度與權(quán)重、自動(dòng)聯(lián)想、拼寫糾錯(cuò)等高級(jí)功能。因此,可以使用 ElasticSearch 作為關(guān)系型數(shù)據(jù)庫(kù)全文搜索的功能補(bǔ)充,將要進(jìn)行全文搜索的數(shù)據(jù)緩存一份到 ElasticSearch 上,達(dá)到處理復(fù)雜的業(yè)務(wù)與提高查詢速度的目的。
ElasticSearch 不僅僅適用于搜索場(chǎng)景,還非常適合日志處理與分析的場(chǎng)景。著名的 ELK 日志處理方案,由 ElasticSearch、Logstash 和 Kibana 三個(gè)組件組成,包括了日志收集、聚合、多維度查詢、可視化顯示等。
14) ObjectId 規(guī)則
[0,1,2,3] [4,5,6] [7,8] [9,10,11]
時(shí)間戳 |機(jī)器碼 |PID |計(jì)數(shù)器
前四位是時(shí)間戳,可以提供秒級(jí)別的唯一性。
接下來(lái)三位是所在主機(jī)的唯一標(biāo)識(shí)符,通常是機(jī)器主機(jī)名的散列值。
接下來(lái)兩位是產(chǎn)生ObjectId的PID,確保同一臺(tái)機(jī)器上并發(fā)產(chǎn)生的ObjectId是唯一的。
前九位保證了同一秒鐘不同機(jī)器的不同進(jìn)程產(chǎn)生的ObjectId時(shí)唯一的。
最后三位是自增計(jì)數(shù)器,確保相同進(jìn)程同一秒鐘產(chǎn)生的ObjectId是唯一的。
15) 聊聊 MongoDB 使用場(chǎng)景
高伸縮性的場(chǎng)景
MongoDB 非常適合高伸縮性的場(chǎng)景,它是可擴(kuò)展性的表結(jié)構(gòu)?;谶@點(diǎn),可以將預(yù)期范圍內(nèi),表結(jié)構(gòu)可能會(huì)不斷擴(kuò)展的 MySQL 表結(jié)構(gòu),通過(guò) MongoDB 來(lái)存儲(chǔ),這就可以保證表結(jié)構(gòu)的擴(kuò)展性。
日志系統(tǒng)的場(chǎng)景
日志系統(tǒng)數(shù)據(jù)量特別大,如果用 MongoDB 數(shù)據(jù)庫(kù)存儲(chǔ)這些數(shù)據(jù),利用分片集群支持海量數(shù)據(jù),同時(shí)使用聚集分析和 MapReduce 的能力,是個(gè)很好的選擇。
分布式文件存儲(chǔ)
MongoDB 還適合存儲(chǔ)大尺寸的數(shù)據(jù),之前介紹的 GridFS 存儲(chǔ)方案,就是基于 MongoDB 的分布式文件存儲(chǔ)系統(tǒng)。
16) 倒排索引
倒排索引(英語(yǔ):Inverted index),也常被稱為反向索引、置入檔案或反向檔案,是一種索引方法,被用來(lái)存儲(chǔ)在全文搜索下某個(gè)單詞在一個(gè)文檔或者一組文檔中的存儲(chǔ)位置的映射。它是文檔檢索系統(tǒng)中最常用的數(shù)據(jù)結(jié)構(gòu)。
有兩種不同的反向索引形式:
一條記錄的水平反向索引(或者反向檔案索引)包含每個(gè)引用單詞的文檔的列表。
一個(gè)單詞的水平反向索引(或者完全反向索引)又包含每個(gè)單詞在一個(gè)文檔中的位置。
17) 聊聊 ElasticSearch 使用場(chǎng)景
全文搜索,這個(gè)是用的最多的。加上分詞插件、拼音插件什么的可以做成強(qiáng)大的全文搜索引擎。
數(shù)據(jù)庫(kù),挺奇葩的用法,因?yàn)镋S存數(shù)相同數(shù)據(jù),更費(fèi)空間,不過(guò)確實(shí)不錯(cuò),因?yàn)樗膹?qiáng)大統(tǒng)計(jì)分析匯總能力,再加上分布式P2P擴(kuò)展能力,現(xiàn)在硬件又那么便宜,所以就有人拿來(lái)當(dāng)數(shù)據(jù)庫(kù)了。
在線統(tǒng)計(jì)分析引擎,日志系統(tǒng)。logstash,不用解釋了吧??梢詫?shí)時(shí)動(dòng)態(tài)分析數(shù)據(jù),很是爽。
評(píng)論
查看更多