MongoDB索引

索引的作用是用來加速查詢,數(shù)據(jù)庫索引與書籍索引類似,創(chuàng)建數(shù)據(jù)庫索引好像確定何如組織書的索引一樣。

# 批量查詢數(shù)據(jù)
for(var i=0; i<30000; i++){
    db.books.insert({name:'book'+i, sort:i});
}
db.books.count();

# 查看查詢計劃
db.books.find(query).explain();
"cursor":"BasicCursor",//說明沒有索引發(fā)揮作用
"nscannedObjects":1000,//理論上要掃描的行數(shù)

# 計算查詢效率
var begin = new Date();
db.books.find({sort:30000});
var end = new Date();
print(end-begin);

# 創(chuàng)建索引,1表示正序,-1表示倒序。
db.books.ensureIndex({sort:1});
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1.0
}

explain

只要對游標調(diào)用explain()會返回一個文檔而非游標本身,explain()會返回查詢使用的索引情況,耗時及掃描文檔數(shù)的統(tǒng)計信息。

強制查詢使用指定索引

# 指定索引必須是已經(jīng)創(chuàng)建了的索引
db.books.find({name:'bookname1', sort:1}).hint({name:-1})

# 查看數(shù)據(jù)庫已建立的索引
db.system.indexes.find();
db.system.namespaces.find();

1 創(chuàng)建索引

索引提高查詢速度,但會降低寫入速度,權(quán)衡常用查詢字段,不必在太多字段上創(chuàng)建索引。在MongoDB中索引可按字段升序或降序來創(chuàng)建,便于排序。默認使用btree來組織索引文件,在2.4版本后允許建立hash索引。

  • 創(chuàng)建索引時索引的方向,1為正序索引,-1為倒序索引。
  • 索引的創(chuàng)建在提高查詢性能的同時會影響插入的性能,對于經(jīng)常查詢少插入的文檔可考慮使用索引。
  • 復(fù)合索引要注意索引的先后順序
  • 索引不是萬能的
  • 排序時大數(shù)據(jù)量可考慮添加索引

1.1 索引類型

索引的作用類型分為單列索引、多列索引、子文檔索引。

# 查看查詢計劃
db.books.find(query).explain()
"cursor":"BasicCursor",//說明沒有索引發(fā)揮作用
"nscannedObjects":1000,//理論上要掃描的行數(shù)

# 創(chuàng)建單列索引
db.books.sureIndex({field:1/-1})
# 創(chuàng)建多列索引(復(fù)合索引)
db.books.sureIndex({field:1/-1, field:1/-1...})
# 創(chuàng)建子文檔索引
db.books.sureIndex({field.subfield:1/-1})

# 查看查詢計劃
db.books.find(query).explain()
"cursor":"BtreeCursor sn_1",//使用btree索引
"nscannedObjects":1000,//理論上要掃描的行數(shù)

創(chuàng)建索引的缺點是每次插入、更新、刪除時會產(chǎn)生額外的開銷。這是因為數(shù)據(jù)庫不但需要執(zhí)行這些操作,還需將這些操作在集合中的索引中標記。因此,要盡可能少創(chuàng)建索引。每個集合默認最大索引個數(shù)為64個。

# 查看當前索引狀態(tài)
db.books.getIndexes()

一般來說或要是查詢返回集合中一半以上的結(jié)果,用表掃描會比幾乎每條文檔都查詢索引要高效。查詢是否存在某個鍵或檢查某個布爾值類型,使沒必要建立索引的。

創(chuàng)建索引時需考慮什么呢?

  • 會做什么樣的查詢呢?其中哪些鍵需要索引呢?
  • 每個鍵的索引方向是怎樣的呢?
  • 如何應(yīng)對擴展?有沒有不同的鍵的排列可使用常用數(shù)據(jù)更多地保留在內(nèi)存中?

1.2 索引名稱

集合中每個索引默認使用字符串命名并具有唯一性,其格式為 keyname1_dir1_keyname2_dir2_..._keynameN_dirNkeyname表示索引的鍵,dir表示索引的方向(1正序 -1逆序)。索引太多時可手工指定索引名稱。

# 創(chuàng)建索引同時指定索引名稱
db.books.ensureIndex({name:-1}, {name:'bookname'});
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 2,
    "numIndexesAfter" : 3,
    "ok" : 1.0
}
# 為內(nèi)嵌文檔的鍵建立索引
db.blogs.ensureIndex({'comments.date': 1});

1.3 排序索引

隨著集合的增長,需針對查詢中大量的排序做索引。若對無索引的鍵調(diào)動sort,MongoDB需將所有數(shù)據(jù)提取到內(nèi)存來排序??勺鰺o序排序時有上限的,是不可能在內(nèi)存中做T級別的數(shù)據(jù)排序。一旦集合達到不能再內(nèi)存中排序,MongoDB會報錯。按照排序來索引以便讓MongoDB按順序提取數(shù)據(jù),在排序大數(shù)據(jù)時不必擔心耗光內(nèi)存。

創(chuàng)建索引時,程序執(zhí)行過程會暫時鎖表,該如何解決呢?

# 為了不影響查詢,創(chuàng)建索引可在后臺執(zhí)行。
db.books.ensureIndex({name:-1}, {background:true})

通常來說要盡量避免讓服務(wù)器做表掃描,因為集合很大時會非常慢。實踐證明,一定要創(chuàng)建查詢中用到的所有健的索引。

2 刪除索引

# 精確刪除
db.books.dropIndex({field:1/-1});//刪除某列字段的單個索引
db.runCommand({dropIndexes:'name', index:'name_1'});

# 批量刪除
db.books.dropIndexes();//刪除所有索引
db.runCommand({dropIndexes:'name', index:'*'})

3 索引性質(zhì)

3.1 唯一索引

建立唯一索引可解決插入重復(fù)的數(shù)據(jù),以確保集合文檔指定鍵是唯一值。

db.books.ensureIndex({name:-1}, {unique:true});

在插入數(shù)據(jù)時并不檢查文檔是否已經(jīng)插入過,為避免插入的文檔包含于唯一鍵重復(fù)的值,可能要用安全插入才能滿足要求。這樣,在插入文檔時會看到存在重復(fù)鍵錯誤的提示。

默認的_id與普通的唯一索引的區(qū)別是,_id的索引時無法刪除的。

創(chuàng)建索引后若無對應(yīng)的鍵,索引會將其作為null存儲。若對鍵建立唯一索引,但插入了多個缺少該索引鍵的文檔,則由于文檔包含null值而導(dǎo)致插入失敗。

消除重復(fù)

倘若建立唯一索引之前已存在重復(fù)數(shù)據(jù),該怎么辦呢?可將包含重復(fù)值的文檔都刪掉,dropDups選項可保留發(fā)現(xiàn)的第一個文檔,而刪除剩余具有重復(fù)值的文檔。對于重要數(shù)據(jù)而言,應(yīng)寫腳本做預(yù)處理比較穩(wěn)妥。

db.books.ensureIndex({name:-1}, {unique:true, dropDups:true})

復(fù)合唯一索引

創(chuàng)建復(fù)合唯一索引時,單個鍵值可相同,只要所有健的值組合起來不同即可。

GridFS是MongoDB中存儲大文件的標準方式,用到了復(fù)合唯一索引。存儲文件內(nèi)存的集合有一個復(fù)合唯一索引{files_id:1, n:1}。

3.2 稀疏索引

若針對字段做索引時且不含字段的文檔,將不建立索引。與之相對的是普通索引,它會把文檔的字段值默認為NULL并建立索引。稀疏索引適用于小部分文檔含有某字段時使用。

db.collection.ensureIndex({field:1/-1}, {sparse:true})

3.3 哈希索引

btree和二叉樹,對于順序讀取具有優(yōu)勢。hash取決于hash算法,根據(jù)hash算法獲得硬盤保存位置,對于散列的數(shù)據(jù),僅通過hash計算即可獲取數(shù)據(jù),由于天生無順序,因此適合于離散的數(shù)據(jù)。

哈希索引速度比普通索引快,但不能對范圍查詢進行優(yōu)化,適用于隨機性強的散列數(shù)據(jù)。

db.collection.ensureIndex({field:'hashed'})

4 重建索引

數(shù)據(jù)表經(jīng)多次修改后導(dǎo)致文件產(chǎn)生空洞,索引文件也是如此。因此可通過重建索引來提高索引的查詢效率,類似MySQL的optimize表。

db.collection.reIndex();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容