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

歡迎訪問 生活随笔!

生活随笔

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

数据库

使用NOSQL的MongoDB时建立索引需要注意的几点建议和Explain优化分析

發(fā)布時間:2024/8/26 数据库 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用NOSQL的MongoDB时建立索引需要注意的几点建议和Explain优化分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
第一,MongoDB索引和MySQL索引非常相似并且對于MySQL的索引優(yōu)化有很多也適用于MongoDB。
第二,更重要的是,這些索引的建議對你的應用提高也是有限的。
對于應用的最佳索引策略應該基于很多的重要因素。包含了你期望查詢的類型,
數(shù)據(jù)讀取與寫入的比率,甚至于你服務器的空閑內存。意思就是,
需要對線上的產品做很多的測試剖析工作,才能調整出最佳的索引策略。
沒有什么好的方法可以替代實際經驗的。

索引策略

?

下面有些索引的基本法則
創(chuàng)建的索引要匹配查詢。
如果你僅僅要查詢單個字段。索引這個字段即可。如
db.posts.find({ slug : 'state-of-mongodb-2010' }) 這個例子中,唯一索引是最佳的
db.posts.ensureIndex({ slug: 1 }, {unique: true}); 然而,一般都查詢多個鍵并且排序結果。這種情況,組合索引是最佳的,例子如下
db.comments.find({ tags : 'mongodb'}).sort({ created_at : -1 }); 創(chuàng)建的索引如下
db.comments.ensureIndex({tags : 1, created_at : -1}); 要注意的是如果我們按照升序排序created_at。索引效率就低下了。
每個查詢一個索引。
有的時候查詢多個鍵,需要多個索引。在MongoDB中,這么做沒問題。
如果你有個查詢要匹配多個鍵,并且你想更有效地使用索引,請使用組合索引。
要確定所有的索引都在RAM中。
Shell中提供了一個查看索引大小的命令,如下:
db.comments.totalIndexSize(); 65443 如果你的查詢有點遲緩,你應該查看下索引是否都存入到RAM中了。
一個實例,如果你運行在4GB的RAM機器并且有3GB的索引,那么索引可能并不能全存在RAM中。
你需要添加RAM以及/或者校驗實際的索引使用量。
要小心單鍵索引的低選擇性。
假使你有個字段叫做'status',就有兩個值new和processed。
如果在status上創(chuàng)建索引那么這就是個低選擇性的索引。
意味著,查詢中沒有什么優(yōu)勢并且還占大量的空間。
一個更好一點的策略,當然依賴具體查詢需求,可以創(chuàng)建組合索引包括這個低選擇性的字段。
舉例來說,你可以創(chuàng)建一個組合索引在status和created_at字段上。
另一個選擇,當然也依賴你的需求,可以分離collection, 一個狀態(tài)一個。
當然這些建議一定要進行測試,選擇最優(yōu)的方案。
使用explain.
MongoDB提供了一個explain命令, 用來查看查詢的過程并且可以查看是否使用縮影。explain可以在驅動中使用,也可以在SHELL中使用:
db.comments.find({ tags : 'mongodb'}).sort({ created_at : -1 }).explain(); 返回了很多有用的信息。包含了檢索的條數(shù),消耗的毫秒數(shù),優(yōu)化器嘗試的索引以及最終所使用的索引。
如果你從來沒有使用過explain,請開始使用吧。
理解explain的輸出.
explain輸出主要有三個字段:
cursor: 游標不是? BasicCursor就是 ? BtreeCursor . 第二種意味著使用了索引。
nscanned: 掃描document的行數(shù)。
n: 查詢返回的行數(shù)。你希望n的值和nsanned值接近。要避免做collection的掃描,
也就是訪問所有的document。
millis: 查詢完成的毫秒數(shù)。這個對于比較索引和非索引性能非常有用。
要關注應用讀/寫( read/write) 比率

這個很重要,因為,添加索引意味著添加,更新,刪除操作變慢。

如果你的應用是偏向于讀取,使用索引是非常好的事情。

但是如果你的應用偏向于寫,那么創(chuàng)建索引就要小心了。增加索引都很影響寫入的性能。

一般來說, 不要隨便添加索引。索引應該按照你的查詢來添加。

添加索引的理由總是很多的, 以及要進行大量的測試選擇合適的索引策略。

索引特性

組合索引有許多特性要記住。

下面的例子都假想在 a, b, c上創(chuàng)建組合索引。因此創(chuàng)建索引語句如下

db.foo.ensureIndex({a: 1, b: 1, c: 1})

?

1. 排序的列一定要在索引的最后。

好的:

find(a=1).sort(a)
find(a=1).sort(b)
find(a=1, b=2).sort(c)

不好的:

find(a=1).sort(c)
即使c是索引的最后一列,a列是所使用的最后一列,因此你只能通過a或者b列進行排序。
2,3 ,4在1.6+已經不適用了。推薦使用1.6+以上版本。
?
5. MongoDB's $ne 或者$nin 操作在索因傷是無效的。
當要排除很少的documents。最好的方法就是在MongoDB查詢出結果,在服務端進行排除。

?

?

=============

MongoDB范圍查詢的索引優(yōu)化

http://blog.nosqlfan.com/html/4117.html

我們知道,MongoDB的索引是B-Tree結構的,和MySQL的索引非常類似。所以你應該聽過這樣的建議:創(chuàng)建索引的時候要考慮到sort操作,盡量把sort操作要用到的字段放到你的索引后面。但是有的情況下,這樣做反而會使你的查詢性能更低。

問題

比如我們進行下面這樣的查詢:

db.collection.find({"country": "A"}).sort({"carsOwned": 1})

查詢條件是 {“country”: “A”},按 carsOwned 字段的正序排序。所以索引就很好建了,直接建立 country , carsOwned 兩個字段的聯(lián)合索引即可。像這樣:

db.collection.ensureIndex({"country": 1, "carsOwned": 1})

我們來看一個稍微復雜一點的查詢:

db.collection.find({"country": {"$in": ["A", "G"]}}).sort({"carsOwned": 1})

這回我們是要查詢 country 為 A 或者 G 的數(shù)據(jù)條目,結果同樣按 carsOwned 字段排序。

如果我們還使用上面的索引,并且使用 explain() 分析一下這個查詢,就會發(fā)現(xiàn)在輸出中有一個“scanAndOrder” : true 的字段,并且 nscanned 的值可能會比想象中的大很多,甚至指定了 limit 也沒什么效果。

原因

這是什么原因呢,我們先看下面這張圖:

如上圖所未,左邊一個是按 {“country”: 1, “carsOwned”: 1} 的順序建立的索引。而右邊是按{“carsOwned”: 1, ”country”: 1} 順序建立的索引。

如果我們執(zhí)行上面的查詢,通過左邊的索引,我們需要將 country 值為A的(左圖的左邊一支)所有子節(jié)點以及country 值為G的(左圖的右邊一支)所有子節(jié)點都取也來。然后再對取出來的這些數(shù)據(jù)按 carsOwned 值進行一次排序操作。

所以說上面 explain 輸出了一個 “scanAndOrder” : true 的提示,就是說這次查詢,是先進行了scan獲取到數(shù)據(jù),再進行了獨立的排序操作的。

那如果我們使用右邊的索引來做查詢,結果就不太一樣了。我們沒有將排序字段放在最后,而是放在了前面,相反把篩選字段放在了后面。那這樣的結果就是:我們 會從值為1的節(jié)點開始遍歷(右圖的左邊一支),當發(fā)現(xiàn)有 country 值為 A 或 G 的,就直接放到結果集中。當完成指定數(shù)量(指定 limit 個數(shù))的查找后。我們就可以直接將結果返回了,因為這時候,所有的結果本身就是按 carsOwned 正序排列的。

對于上面的數(shù)據(jù)集,如果我們需要2條結果。我們通過左圖的索引需要掃描到4條記錄,然后對4條記錄進行排序才能返回結果。而右邊只需要我們掃描2條結果就能直接返回了(因為查詢的過程就是按需要的順序去遍歷索引的)。

所以,在有范圍查詢(包括$in, $gt, $lt 等等)的時候,其實刻意在后面追加排序索引通常是沒有效果的。因為在進行范圍查詢的過程中,我們得到的結果集本身并不是按追加的這個字段來排的,還需要進 行一次額外的排序才行。而在這種情況下,可能反序建立索引(排序字段在前、范圍查詢字段在后)反而會是一個比較優(yōu)的選擇。當然,是否更優(yōu)也和具體的數(shù)據(jù)集 有關。

總結

總結一下,舉兩個栗子。

當查詢是:

db.test.find({a:1,b:2}).sort({c:1})

那么直接建立 {a:1, b:1, c:1} 或者 {b:1, a:1, c:1} 的聯(lián)合索引即可。

如果查詢是:

db.test.find({a:1,b:{$in:[1,2]}}).sort({c:1})

那么可能建立 {a:1, c:1, b:1} 的聯(lián)合索引會比較合適。當然,這里只是提供了多一種思路,具體是否采用還是需要視你的數(shù)據(jù)情況而定。

來源:architects.dzone.com

=======================MongoDB與傳統(tǒng) 數(shù)據(jù)庫 的使用區(qū)別——批量插入與批量查詢 http://blog.sina.com.cn/s/blog_56545fd301013zav. html

我在百X知道上回答問題時經常遇到類似與這樣的問題:MongoDB有沒有像MySQL一樣的ODBC驅動?MongoDB能不能像MySQL一樣獲取字段名稱或類型。

我的回答是:不行,因為MongoDB不是MySQL。這個回答顯得MongoDB太弱了,我的原意是你不能要求一個物理優(yōu)秀教師幫你輔導數(shù)學,也許他能做到基本的教學,但他很難做到優(yōu)秀數(shù)學教師那么全面。

?

今天討論的問題是:批量插入和批量查詢

昨天在百X知道上有人問起MongoDB的批量插入如何寫,這個我還真沒用過,一方面MongoDB的速度足夠快讓我從來沒有想過去找這種方法,另一方面MongoDB的官網以及API里也找不到這種方法。

那就帶來兩個問題。

問題1:這樣豈不是沒有速度更快的批量插入么?

這個問題毫無技術含量,MongoDB怎么可能會比MySQL慢?這里還是涉及到大家經常用到的傳統(tǒng)關系型數(shù)據(jù)庫和NoSQL的本質區(qū)別問題,NoSQL的每次操作都非常輕量級,小型化,除了數(shù)據(jù)的寫入外基本沒有多余的操作。再舉個栗子:MongoDB就是放東西(數(shù)據(jù))時把東西扔入相應的柜子(數(shù)據(jù)庫)即可,而MySQL則要保持與送東西人的溝通(雙向連接保持),東西的折疊整理分格存儲(事務+有模式)。MySQL的批量插入就是減少了溝通以及分格等過程,而MongoDB本身就不存在這些過程,因此MongoDB就不存在批量插入這個概念了。結論就是,MongoDB的普通插入比MySQL的批量插入還要快,或者說MongoDB的普通插入就是批量插入。

問題2:把多個操作放入一個事務里一起執(zhí)行不就不能實現(xiàn)了?

這個問題更沒有技術含量了,MongoDB有事務么?還是那句,不要把NoSQL當關系型數(shù)據(jù)庫用。那豈不是MongoDB的數(shù)據(jù)完整性和數(shù)據(jù)安全性會很差?這個,還得再重復一遍,MongoDB的設計是為了處理大規(guī)模數(shù)據(jù)的,所以對數(shù)據(jù)完整性要求不是那么嚴格。如果非要較真兒的話,MongoDB也可以處理這種情況,就是getLastError,它會犧牲性能以獲取數(shù)據(jù)操作是否正確,你可以在批量插入一批數(shù)據(jù)后調用一次這個方法,如果出錯,就把這批數(shù)據(jù)重新操作一遍,一批調用getLastError一次,既可保證性能,又可保證數(shù)據(jù)安全。

?

批量查詢

再來說一下批量查詢,這里的批量對應于官網上的batch select的概念,可以理解為一次查詢一批數(shù)據(jù)。很多人在使用數(shù)據(jù)庫的時候會用:

Statement stmt = a.createStatement();

ResultSet rs = stmt.executeQuery(sql);

for(int i = 1; i < 10000; i++){

//read data from rs

}

這樣操作,會把數(shù)據(jù)庫中的數(shù)據(jù)全部讀入內存還是每條數(shù)據(jù)都去數(shù)據(jù)庫中讀一次?實際上兩者都不是,MySQL會把部分數(shù)據(jù)放入內存,如果這部分數(shù)據(jù)讀完了,那么再讀入一部分。因為很久沒用MySQL了,我記得C++的驅動中確實有一個類是用于把全部數(shù)據(jù)都讀入內存的,不過這種方法很少人使用。

MongoDB的查詢是這樣的,你用Cursur去查詢,如果沒有設置batch size這個參數(shù),那么MongoDB默認會返回101條數(shù)據(jù),等到這101條數(shù)據(jù)讀完了,也就是說用戶想讀第102條數(shù)據(jù),那么驅動會再次去MongoDB中獲取后面的一批數(shù)據(jù),這批數(shù)據(jù)不是以個數(shù)記的,而是最大限制4M的大小,將這4M的數(shù)據(jù)返回供用戶繼續(xù)讀,讀完再申請4M。當然,你可以通過batch size來改變這一數(shù)值,如果設置了,那么每次返回都會返回batch size條數(shù)據(jù)。


轉載請注明出處:http://blog.sina.com.cn/s/blog_56545fd301013zav.html ==============如何使用mongoose對一個100萬+的mongodb的表進行遍歷操作 http://cnodejs.org/topic/51508570604b3d512113f1b3 ===================== MongoDB優(yōu)化的幾點原則 http://nosqldb.org/topic/50cac0c8ee680fee79001566 1.查詢優(yōu)化
確認你的查詢是否充分利用到了索引,用explain命令查看一下查詢執(zhí)行的情況,添加必要的索引,避免掃表操作。
2.搞清你的熱數(shù)據(jù)大小
可能你的數(shù)據(jù)集非常大,但是這并不那么重要,重要的是你的熱數(shù)據(jù)集有多大,你經常訪問的數(shù)據(jù)有多大(包括經常訪問的數(shù)據(jù)和所有索引數(shù)據(jù))。使用MongoDB,你最好保證你的熱數(shù)據(jù)在你機器的內存大小之下,保證內存能容納所有熱數(shù)據(jù)。
3.選擇正確的文件 系統(tǒng)
MongoDB的數(shù)據(jù)文件是采用的預分配模式,并且在Replication里面,Master和Replica Sets的非Arbiter節(jié)點都是會預先創(chuàng)建足夠的空文件用以存儲操作日志。這些文件分配操作在一些文件系統(tǒng)上可能會非常慢,導致進程被Block。所以我們應該選擇那些空間分配快速的文件系統(tǒng)。這里的結論是盡量不要用ext3,用ext4或者xfs。
4.選擇合適的硬盤
這里的選擇包括了對磁盤RAID的選擇,也包括了磁盤與SSD的對比選擇。
5.盡量少用in的方式查詢,尤其是在shard上,他會讓你的查詢去被一個shand上跑一次,
如果逼不得已要用的話再每個shard上建索引。
優(yōu)化in的方式是把in分解成一個一個的單一查詢。速度會提高40-50倍
6.合理設計sharding key
increamenting sharding key(增量sharding-key)適合于可劃分范圍的字段,比如integer、float、date類型的,查詢時比較快
random sharding key(隨機sharding-key)適用于寫操作頻繁的場景,而這種情況下如果在一個shard上進行會使得這個shard負載比其他高,不夠均衡,故而希望能hash查詢key,將寫分布在多個shard上進行
考慮復合key作為sharding key, 總的原則是查詢快,盡量減少跨shard查詢,balance均衡次數(shù)少。
mongodb默認是單條記錄16M,尤其在使用GFS的時候,一定要注意shrading-key的設計。
不合理的sharding-key會出現(xiàn),多個文檔,在一個chunks上,同時,因為GFS中存貯的往往是大文件,導致mongodb在做balance的時候無法通過sharding-key來把這多個文檔分開到不同的shard上,
這時候mongodb會不斷報錯
[conn27669] Uncaught std::exception: St9bad_alloc, terminating。最后導致mongodb倒掉。
解決辦法:加大chunks大小(治標),設計合理的sharding-key(治本)。
7.mongodb可以通過profile來監(jiān)控數(shù)據(jù),進行優(yōu)化。
查看當前是否開啟profile功能
用命令db.getProfilingLevel() 返回level等級,值為0|1|2,分別代表意思:0代表關閉,1代表記錄慢命令,2代表全部
開啟profile功能命令為
db.setProfilingLevel(level); #level等級,值同上
level為1的時候,慢命令默認值為100ms,更改為db.setProfilingLevel(level,slowms)如db.setProfilingLevel(1,50)這樣就更改為50毫秒

通過db.system.profile.find() 查看當前的監(jiān)控日志.

總結

以上是生活随笔為你收集整理的使用NOSQL的MongoDB时建立索引需要注意的几点建议和Explain优化分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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