MongoDB設計命名規(guī)范有哪些

MongoDB設計命名規(guī)范有哪些,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

目前創(chuàng)新互聯(lián)已為近1000家的企業(yè)提供了網(wǎng)站建設、域名、虛擬主機、網(wǎng)站托管運營、企業(yè)網(wǎng)站設計、白云網(wǎng)站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

1.       庫

1.       庫名全部小寫,禁止使用任何`_`以外的特殊字符,禁止使用數(shù)字打頭的庫名,如:`123_abc`;

2.       庫以文件夾的形式存在,使用特殊字符或其它不規(guī)范的命名方式會導致命名混亂;

3.       數(shù)據(jù)庫名最多為64字符;

4.       在創(chuàng)建新的庫前應盡量評估該庫的體積、QPS等,提前與DBA討論是應該新建一個庫還是專門為該庫創(chuàng)建一個新的集群;

某開發(fā)在拿到DBA提供的MongoDB后由于MongoDB的權限控制比較寬松,導致該業(yè)務的開發(fā)在創(chuàng)建集合的時候懶得與DBA討論,而是隨意的將所有集合都創(chuàng)建在一個庫中,最初并沒有什么問題,因為業(yè)務的請求量并不大。半年后,該業(yè)務增長到了一個比較大的量級,而此時開發(fā)人員上線了一個新的項目,該項目的寫入量很大,大部分都為批量更新,由于所有集合都存放在一個庫中,這個新項目的批量更新帶來了頻繁的鎖、I/O平均等。最后開發(fā)配合DBA一起將該庫拆散到了多個新的庫中,將一庫N集合轉(zhuǎn)換為單庫單集合,性能問題迎刃而解。

2.       集合

1.       集合名全部小寫,禁止使用任何`_`以外的特殊字符,禁止使用數(shù)字打頭的集合名,如:`123_abc`,禁止system打頭; system是系統(tǒng)集合前綴;

2.       集合名稱最多為64字符;

3.       一個庫中寫入較大的集合會影響其它集合的讀寫性能,如果業(yè)務比較繁華的集合在一個DB中,建議最多80個集合,同時也要考慮磁盤I/O的性能;

4.       如果評估單集合數(shù)據(jù)量較大,可以將一個大表拆分為多個小表,然后將每一個小表存放在獨立的庫中或者sharding分表;

5.       MongoDB的集合擁有“自動清理過期數(shù)據(jù)”的功能,只需在該集合中文檔的時間字段增加一個TTL索引即可實現(xiàn)該功能,但需要注意的是該字段的類型則必須是mongoDate(),一定要結合實際業(yè)務設計是否需要;

6.       設計輪詢集合---集合是否設計為Capped限制集,一定要結合實際業(yè)務設計是否需要;

7.       創(chuàng)建集合規(guī)則

不同的業(yè)務場景是可以配置進行不同的配置;

a.       如果是讀多寫少的表在創(chuàng)建時我們可以盡量將 page size 設置的比較小,比如 16KB,如果表數(shù)據(jù)量不太大(

"internal_page_max=16KB,leaf_page_max=16KB,leaf_value_max=8KB,os_cache_max=1GB"

b.       如果這個讀多寫少的表數(shù)據(jù)量比較大,可以為其設置一個壓縮算法,例如:

"block_compressor=zlib,internal_page_max=16KB,leaf_page_max=16KB,leaf_value_max=8KB"

c.       注意:該zlib壓縮算法不要使用,對cpu消耗特別大,如果使用snapp消耗20% cpu,而且使用zlib能消耗90%cpu,甚至100%

d.       如果是寫多讀少的表,可以將 leaf_page_max 設置到 1MB,并開啟壓縮算法,也可以為其制定操作系統(tǒng)層面 page cache 大小的os_cache_max 值,讓它不會占用太多的 page cache 內(nèi)存,防止影響讀操作;

e.       案例

db.createCollection(

   "logs",

   { storageEngine: { wiredTiger: {configString: "internal_page_max=16KB,leaf_page_max=16KB,leaf_value_max=8KB,os_cache_max=1GB" } } }

)

f.       說明

讀多寫少的表

internal_page_max=16KB   默認為4KB

leaf_page_max=16KB       默認為32KB

leaf_value_max=8KB       默認為64MB

os_cache_max=1GB         默認為0

讀多寫少的表  而且數(shù)據(jù)量比較大

block_compressor=zlib    默認為snappy

internal_page_max=16KB   默認為4KB

leaf_page_max=16KB       默認為32KB

leaf_value_max=8KB       默認為64MB

3.       文檔

1.       文檔中的key禁止使用任何`_`以外的特殊字符;

2.       盡量將同樣類型的文檔存放在一個集合中,將不同類型的文檔分散在不同的集合中;相同類型的文檔能夠大幅度提高索引利用率,如果文檔混雜存放則可能會出現(xiàn)查詢經(jīng)常需要全表掃描的情況;

3.       禁止使用_id,如:向_id中寫入自定義內(nèi)容;

某業(yè)務的MongoDB在放量后出現(xiàn)嚴重的寫入性能問題,大致為:寫入達到300/s的時候IO跑滿,排查中發(fā)現(xiàn),該業(yè)務在設計的時候為了方便, 而將_id中寫入了無序的類似md5的數(shù)據(jù)。MongoDB的表與InnoDB相似,都是索引組織表,數(shù)據(jù)內(nèi)容跟在主鍵后,而_id是MongoDB中的默認主鍵,一旦_id的值為非自增,當數(shù)據(jù)量達到一定程度之后,每一次寫入都可能導致主鍵的二叉樹大幅度調(diào)整,這將是一個代價極大的寫入, 所以寫入就會隨著數(shù)據(jù)量的增大而下降,所以一定不要在_id中寫入自定義的內(nèi)容。

4.       盡量不要讓數(shù)組字段成為查詢條件

某業(yè)務在一個表的數(shù)組字段上創(chuàng)建了一個索引,創(chuàng)建完畢之后發(fā)現(xiàn)表體積增大了很多很多,排查發(fā)現(xiàn)是由于索引體積的大幅度增大導致在MongoDB中,如果為一個數(shù)組字段添加索引,那么MongoDB會主動為這個數(shù)組中的所有元素依次添加獨立索引,例如: 為數(shù)組字段{a:[x,y,z]}添加索引{a:1},實際上添加的索引為:

{a:[x:1]}

{a:[y:1]}

{a:[z:1]}

該業(yè)務的數(shù)組字段中有11個元素,那么等于一次創(chuàng)建了11條索引,這是索引體積大幅度增大的根本原因。另外,如果組合索引中存在數(shù)組字段,那么MongoDB會為每一個元素與其它字段的組合創(chuàng)建一個獨立的索引,例如: 為數(shù)組字段{a:[x,y,z]}和{b:qqq}添加索引{a:1,b:1},實際上添加的索引為:

{a:[x:1],b:1}

{a:[y:1],b:1}

{a:[z:1],b:1}

如果一個組合索引中存在兩個數(shù)組字段,那么索引的數(shù)量將是兩個數(shù)組字段中元素的笛卡兒積,所以MongoDB不允許索引中存在一個以上的數(shù)組字段。

5.       如果字段較大,應盡量壓縮存放

某業(yè)務上線后一直很正常,但在放量3倍之后發(fā)現(xiàn)MongoDB服務器的網(wǎng)卡流量報警,IO壓力報警,排查中發(fā)現(xiàn),該業(yè)務講一個超長的文本字段存放在MongoDB中,而這個字段的平均體積達到了7K。在并發(fā)為2000QPS的場景下,每次取出1~20條數(shù)據(jù),導致這個MongoDB每秒鐘要發(fā)送將近100MB的數(shù)據(jù),而對于數(shù)據(jù)庫而言,讀寫均為隨機IO,所以在如此大的數(shù)據(jù)吞吐場景中,IO達到了報警閾值。

由于文本是一個容易壓縮的樣本, 所以我們對該字段進行了壓縮存放,使其平均體積降低到了2K,而解壓在業(yè)務端進行處理,最終將吞吐降低到了20MB/S左右。

如果字段較大且會成為查詢條件,例如一長串的url,盡量轉(zhuǎn)成md5后存放

某業(yè)務上線前進行壓力測試,測試中發(fā)現(xiàn)某個場景下的查詢性能不夠理想,排查中發(fā)現(xiàn)該場景的查詢條件類似:{url:xxxx},而url字段中的值大部分都很長很長,該字段的平均體積達到了0.5K,在這種情況下索引的體積會變得很大從而導致雖然請求雖然能夠走索引但效率并不夠理想,于是dba配合業(yè)務開發(fā)一起對該場景進行優(yōu)化:

1.將該字段的存放的內(nèi)容由真實的url改為url內(nèi)容md5后的值,字段體積得到了大幅度縮小,固定在了32位

2.查詢時,用戶請求通過url查詢,而此時程序會將該url進行md5,然后用得到的值進行查詢,由于所以體積大幅度縮小,所以查詢速度有了極大的提高,優(yōu)化完畢后再次進行壓力測試,性能達標,為之前的6倍。

6.       由于MongoDB是大小寫敏感的,如果字段無需大小寫敏感,為了提高查詢效率應盡量存放統(tǒng)一了大小寫后的數(shù)據(jù),如:全部小寫或為該字段增加一個統(tǒng)一了大小寫的輔助字段;

某業(yè)務需要根據(jù)字段{a:XxX}來進行查詢,在MongoDB中a的值是大小寫敏感的,并且無法配置為忽略大小寫,但該業(yè)務場景為了滿足查詢需求而需要忽略大小寫,這個大小寫敏感與否的矛盾導致業(yè)務需要使用正則來進行匹配:{a:/xxx/i},i參數(shù)在正則中表示忽略大小寫,上線后發(fā)現(xiàn), 查詢性能非常低下,在一個擁有200萬文檔的集合中一次查詢需要消耗2.8~7秒,并發(fā)達到50QPS的時候MongoDB實例所在服務器的CPU就跑到了973%。

MongoDB在查詢條件中使用正則的時候,能夠像普通精確匹配一樣使用索引達到高效率的查詢,但一旦使用了參數(shù)i來忽略大小寫查詢優(yōu)化器就需要對每一個數(shù)據(jù)的大小寫進行調(diào)整然后再進行匹配,此時這個請求就變成了全表掃描,這就是效率低下的根本原因。

對于這種場景可以采用新建一個統(tǒng)一了大小的字段,例如全部小寫:假設原字段為:{a:aAbB},那么為其添加一個全部為小寫的對應字段:{a_low:aabb}然后通過字段a_low進行查詢就能達到精確匹配,按照該方案改進后,該場景的查詢耗時降低到了2毫秒雖然新增字段導致實例會變大一些,但對于換來性能的大幅度提升還是非常值得的。

7.       不要存放太長的字符串,如果這個字段為查詢條件,那么確保該字段的值不超過1KB;

8.       MongoDB的索引僅支持1K以內(nèi)的字段,如果你存入的數(shù)據(jù)長度超過1K,那么它將無法被索引;

4.       索引

1.       MongoDB 的組合索引使用策略與 MySQL 一致,遵循“最左原則”;

2.       索引名稱長度不要超過128字符;

3.       應盡量綜合評估查詢場景,通過評估盡可能的將單列索引并入組合索引以降低所以數(shù)量,結合1,2點;

MongoDB的組合索引規(guī)則和MySQL一樣,都遵循最左原理,假設一個組合索引為:{a:1,b:1,c:1},那么以下條件的查詢是可以被用到的:

{a:1}

{a:1,b:2}

{a:1,b:2,c:3}

{}

以下條件的查詢是不能用到索引的:

{b:1}

{b:1:c:2}

{c:2}

另外在設計索引的時候可以通過該原理減少索引的數(shù)目,如果需要通過{a:xxx}或{a:xxx,b:xxx}來進行查詢,那么創(chuàng)建索引:

{a:1,b:1}

即可同時滿足這兩個查詢場景而無需再單獨創(chuàng)建{a:1}索引。

4.       在創(chuàng)建組合索引的時候,應評估索引中包含的字段,盡量將數(shù)據(jù)基數(shù)大(唯一值多的數(shù)據(jù))的字段放在組合索引的前面;

某業(yè)務某場景下的查詢十分緩慢,大概需要1.7秒左右,需要進行調(diào)優(yōu),該場景的查詢和對應索引如下:

查詢:{name:baidu,status:0}

索引:{status:1,name:1}

乍一看沒什么問題,因為查詢和索引十分匹配,但對該集合分析后發(fā)現(xiàn)該集合一共有150萬文檔,而status=0的有1499930由于這基本上占了99%的文檔數(shù)目(數(shù)據(jù)基數(shù)很小),所以導致雖然使用了索引,但依然需要從149萬行數(shù)據(jù)中找到name=baidu的數(shù)據(jù)但name字段則有大量不同的數(shù)據(jù)(數(shù)據(jù)基數(shù)很大),所以如果將該組合索引調(diào)整為name在前,該查詢即可先通過name字段抽出較少的數(shù)據(jù),再通過status進行過濾,就快了:

{name:1.status:1}調(diào)整后查詢耗時降低到3~5毫秒。

5.       在數(shù)據(jù)量較大的時候,MongoDB 索引的創(chuàng)建是一個緩慢的過程,所以應當在上前線或數(shù)據(jù)量變得很大前盡量評估,按需創(chuàng)建會用到的索引;

6.       MongoDB 支持 TTL 索引,該索引能夠按你的需要自動刪除XXX秒之前的數(shù)據(jù)并會盡量選擇在業(yè)務低峰期執(zhí)行刪除操作;看業(yè)務是否需要這一類型索引;

7.       如果你存放的數(shù)據(jù)是地理位置信息,比如:經(jīng)緯度數(shù)據(jù)。那么可以在該字段上添加 MongoDB 支持的地理索引:2d 及2dsphere,但他們是不同的,混用會導致結果不準確;

2d:只能用于點對點索引,適用于平面地圖和時間連續(xù)的數(shù)據(jù),比如非常適用于游戲地圖【2dsphere:允許指定點、線和多邊形。適用于地球表面類型的地圖(球體) 】如果在球體表面創(chuàng)建2d索引,則會導致極點附近出現(xiàn)大量扭曲變形,最終導致結果不準確;

8.       MongoDB 的全文索引目前仍然處于“實驗”階段,性能并不夠理想,當前不建議使用;

9.       從 MongoDB2.4開始,支持索引的 ICP 功能,可以通過其合理減少索引數(shù)量;

從 MongoDB2.4開始,組合索引能夠被更有效的利用,如:

索引{x:1,y:1,z:1}可以被查詢{x:1,z:1}所利用如果x字段的數(shù)據(jù)基數(shù)很大,而該條件匹配到的數(shù)據(jù)有很少,在這種情況下無需專門添加{x:1,z:1}索引,索引{x:1,y:1,z:1}即可帶來理想的性能但需要注意的是,ICP 性能并沒有原生的連續(xù)的組合索引效率好,如果發(fā)現(xiàn)效率不佳那么還是需要添加單獨的{x:1,z:1}索引;

10.   創(chuàng)建索引要在后臺創(chuàng)建,避免阻塞業(yè)務正常DML和查詢

db.works.createIndex({plan:1,trainingpoints:1,cmsOrder:1,stateValue:1},{background:true})

a.       添加唯一索引

db.bodys.createIndex({user:1,date:-1},{unique:true,background:true}) 唯一索引  3.2以下必須這樣加唯一索引;

b.       添加帶有數(shù)組好其他列的索引

db.antis.createIndex({"action.last":1,refe_type:1,_id:1},{background:true})

其中action.last是數(shù)組

MongoDB設計命名規(guī)范有哪些

c.       TTL索引,字段create_date,180天后自動清理數(shù)據(jù)

db.orders.createIndex({"create_date":1},{"expireAfterSeconds":15552000})

d.       案例說明

創(chuàng)建位置和狀態(tài)索引,為了能快速處理“某地未處理訂單”查詢,這是一個多條件的查詢,所以是一個復合索引,

status字段放在前面,因為多數(shù)的查詢都會依賴狀態(tài)字段

db.order.createIndex({"status":1, "delivery.city":1,"delivery.address":1})

在這個Demo里,還有一種加快查詢速度的方法就是,創(chuàng)建一個只包含指定狀態(tài)的一個Partial Indexes索引。

比如status必須為delivering 才加入到索引中,有效控制索引的大小,加快查詢速度。

db.order.createIndex({"delivery.city":1,"delivery.address":1},{partialFilterExpression:{'status':{$eq:"delivering"}}})

e.        

11.   創(chuàng)建索引建議:先做等值查詢,在做排序,在做范圍查詢。

5.       實踐操作性能

1.       索引中的-1和1是不一樣的,一個是逆序,一個是正序,應當根據(jù)自己的業(yè)務場景建立適合的索引排序,需要注意的是{a:1,b:-1} 和 {a:-1,b:1}是一樣的;

2.       在開發(fā)業(yè)務的時候盡量檢查自己的程序性能,可以使用explain() 函數(shù)檢查你的查詢執(zhí)行詳情,另外 hint() 函數(shù)相當于 MySQL 中的force index();

3.       查詢中的某些 $ 操作符可能會導致性能低下,如 $ne,$not,$exists,$nin,$or,盡量在業(yè)務中不要使用

a.       $exist:因為松散的文檔結構導致查詢必須遍歷每一個文檔

b.       $ne:如果當取反的值為大多數(shù),則會掃描整個索引

c.       $not:可能會導致查詢優(yōu)化器不知道應當使用哪個索引,所以會經(jīng)常退化為全表掃描

d.       $nin:全表掃描

e.       $or:有多少個條件就會查詢多少次,最后合并結果集,所以盡可能的使用 $in

4.       如果你結合體積大小/文檔數(shù)固定,那么建議創(chuàng)建 capped(封頂)集合,這種集合的寫入性能非常高并無需專門清理老舊數(shù)據(jù),需要注意的是 capped 表不支持r emove() 和update();

5.       在寫入數(shù)據(jù)的時候,如果你需要實現(xiàn)類似 MySQL 中INSERT INTO ON DUPLICATE KEY UPDATE 的功能,那么可以選擇 upsert() 函數(shù);

db.analytice.update(

{"url":"/blog"},

{"$inc":{"visits":1}},

true

)

第3個參數(shù)表示,這是upsert

6.       不要一次取出太多的數(shù)據(jù)進行排序,MongoDB 目前支持對32MB以內(nèi)的結果集進行排序,如果需要排序,那么請盡量限制結果集中的數(shù)據(jù)量;

7.       MongoDB 的聚合框架非常好用,能夠通過簡單的語法實現(xiàn)復雜的統(tǒng)計查詢,并且性能也不錯;

8.       如果需要清理掉一個集合中的所有數(shù)據(jù),那么 remove() 的性能是非常低下的,該場景下應當使用 drop();

remove() 是逐行操作,所以在刪除大量數(shù)據(jù)的時候性能很差;

9.       寫入大量數(shù)據(jù)的時候可以選擇使用 batchInsert,但目前MongoDB 每一次能夠接受的最大消息長度為48MB,如果超出48MB,將會被自動拆分為多個48MB的消息;

10.   在使用數(shù)組字段做為查詢條件的時候,將于覆蓋索引無緣;

這是因為數(shù)組是保存在索引中的,即便將數(shù)組字段從需要返回的字段中剔除,這樣的索引仍然無法覆蓋查詢;

11.   在查詢中如果有范圍條件,那么盡量和定值條件放在一起進行過濾,并在創(chuàng)建索引的時候?qū)⒍ㄖ挡樵冏侄畏旁诜秶樵冏侄吻?

關于MongoDB設計命名規(guī)范有哪些問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關知識。

新聞名稱:MongoDB設計命名規(guī)范有哪些
分享地址:http://muchs.cn/article16/ihiigg.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護微信小程序、營銷型網(wǎng)站建設搜索引擎優(yōu)化、軟件開發(fā)、定制開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設