MongoDB的簡單學習4-性能相關

1、索引管理

簡介:html

MongoDB提供了多樣性的索引支持,索引信息被保存在system.indexes中,MongoDB中的_id字段在建立的時候,默認已經創建了索引,這個索引比較特殊,而且不可刪除,不過Capped Collections例外。git

注意事項:在3.0.0版本前建立索引的方法爲db.collection.ensureIndex(),以後的版本使用db.collection.createIndex(),ensureIndex()還能用,但只是createIndex()的別名。mongodb

1.創建索引   》》 參考文檔

創建索引的函數:ensureIndex()數據庫

例子:在name上創建索引 1(升序), -1(降序) ,eg:>db.c1.ensureIndex({name:1});安全

當系統已經有大量數據時,建立索引很是耗時,須要在後臺執行,只需指定「backgroud:true」便可。性能優化

>db.c1.ensureIndex({age:1},{background:true});bash

 

插入測試數據:>for(i=1;i<=10;i++) {
                        ... db.c1.insert({name:"user"+i,age:i});
                        ... }網絡

查找name爲"user5"的記錄的查詢過程:>db.c1.find({name:"user5"}).explain();app

 

給name增長一個索引:> db.c1.ensureIndex({name:1});ide

createIndex()方法中也能夠設置使用多個字段建立索引(關係型數據庫中稱爲複合索引) :> db.c1.createIndex({name:1,age:-1});

查看如今全部的索引:> db.c1.getIndexKeys();

結果:[ { "_id" : 1 }, { "name" : 1 } ]

查看全部的索引:> db.c1.getIndexes();

> db.c1.getIndexes();
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1 #索引所在的列
		},
		"name" : "_id_", #索引的名稱
		"ns" : "test.c1"
	},
	{
		"v" : 2,
		"key" : {
			"name" : 1 #索引所在的列
		},
		"name" : "name_1", #索引的名稱
		"ns" : "test.c1"
	}
]

2.惟一索引

只須要在ensureIndex命令中指定「unique:true」便可建立惟一索引。

建立惟一索引:> db.c1.ensureIndex({age:1},{unique:1});

查看索引:>db.c1.getIndexKeys();

結果:[ { "_id" : 1 }, { "name" : 1 }, { "age" : 1 } ]

 查看索引:>> db.c1.getIndexes();
此時發現:

#由於有age=10的記錄了,因此再插入age爲10的記錄,報惟一索引錯誤!!
> db.c1.insert({name:"user11",age:10});
WriteResult({
	"nInserted" : 0,
	"writeError" : {
		"code" : 11000,
		"errmsg" : "E11000 duplicate key error collection: test.c1 index: age_1 dup key: { : 10.0 }"
	}
})
>

3.查看索引

查看索引用的命令:getIndexes();

#其中_id是建立集合的時候自動建立的索引,此索引是不可以刪除。
> db.c1.getIndexes();
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "test.c1"
	},
	{
		"v" : 2,
		"key" : {
			"name" : 1
		},
		"name" : "name_1",
		"ns" : "test.c1"
	},
	{
		"v" : 2,
		"unique" : true,
		"key" : {
			"age" : 1
		},
		"name" : "age_1",
		"ns" : "test.c1"
	}
]

4.刪除索引

刪除索引的命令:dropIndexes();

//刪除索引 "name" : "idx_score",
db.hotspot_video.dropIndex("idx_score");

#刪除age索引
> db.c1.dropIndex({age:1});
{ "nIndexesWas" : 3, "ok" : 1 }
> db.c1.getIndexKeys();
[ { "_id" : 1 }, { "name" : 1 } ]

#刪除全部的索引
> db.c1.dropIndexes();
{
	"nIndexesWas" : 2,
	"msg" : "non-_id indexes dropped for collection",
	"ok" : 1
}
> db.c1.getIndexes();
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "test.c1"
	}
]

#如上,能夠看到_id的索引是不能刪除的!

2、性能優化

簡介:

MongoDB提供了一個explain命令讓咱們獲知系統如何查詢請求。利用explain命令咱們能夠很好的觀察系統如何使用索引來加快檢索,同時能夠針對性優化索引。

1.explain()

MongoDB3.0以上,explain()有三個可選的模式有」queryPlanner」, 「executionStats」, 和 「allPlansExecution」.傳入true表明allPlansExecution mode, 傳入false或者默認爲queryPlanner mode. 

 

#查看執行過程!
> db.c1.find({name:"user5"}).explain("executionStats");
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "test.c1",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"name" : {
				"$eq" : "user5"
			}
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",
			"filter" : {
				"name" : {
					"$eq" : "user5"
				}
			},
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true, ###執行是否成功
		"nReturned" : 1, ### 返回的文檔數
		"executionTimeMillis" : 0,  ###執行的時間
		"totalKeysExamined" : 0,   ###索引掃描條數
		"totalDocsExamined" : 10,  ###文檔掃描條數
		"executionStages" : {
			"stage" : "COLLSCAN", ### 表明CollectionScan-集合掃描!
			"filter" : {
				"name" : {
					"$eq" : "user5"
				}
			},
			"nReturned" : 1, ### 表明返回的個數!
			"executionTimeMillisEstimate" : 0, 
			"works" : 12,
			"advanced" : 1,  ###過程當中應該返回的文檔數量
			"needTime" : 10,
			"needYield" : 0,  ###過程當中被打斷的次數
			"saveState" : 0,
			"restoreState" : 0,
			"isEOF" : 1,  ###指定查詢是否已經結束
			"invalidates" : 0,
			"direction" : "forward", ###查詢的方式
			"docsExamined" : 10 ###表明掃描行數爲10
		}
	},
	"serverInfo" : {
		"host" : "localhost",
		"port" : 27017,
		"version" : "3.6.4",
		"gitVersion" : "d0181a711f7e7f39e60b5aeb1dc7097bf6ae5856"
	},
	"ok" : 1
}

創建索引後的查找:

###爲name創建索引
> db.c1.createIndex({name:1});
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}
> db.c1.find({name:"user5"}).explain("executionStats");
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "test.c1",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"name" : {
				"$eq" : "user5"
			}
		},
		"winningPlan" : {
			"stage" : "FETCH",
			"inputStage" : {
				"stage" : "IXSCAN",
				"keyPattern" : {
					"name" : 1
				},
				"indexName" : "name_1",
				"isMultiKey" : false,
				"multiKeyPaths" : {
					"name" : [ ]
				},
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 2,
				"direction" : "forward",
				"indexBounds" : {
					"name" : [
						"[\"user5\", \"user5\"]"
					]
				}
			}
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 1,
		"executionTimeMillis" : 1,
		"totalKeysExamined" : 1, ###索引掃描條數
		"totalDocsExamined" : 1, ###未文檔掃描條數
		"executionStages" : {
			"stage" : "FETCH",  
			"nReturned" : 1,
			"executionTimeMillisEstimate" : 0,
			"works" : 2,
			"advanced" : 1,
			"needTime" : 0,
			"needYield" : 0,
			"saveState" : 0,
			"restoreState" : 0,
			"isEOF" : 1,
			"invalidates" : 0,
			"docsExamined" : 1,
			"alreadyHasObj" : 0,
			"inputStage" : {
				"stage" : "IXSCAN", ###創建索引後的查找
				"nReturned" : 1, ###創建索引後仍是返回一條數據
				"executionTimeMillisEstimate" : 0,
				"works" : 2,
				"advanced" : 1,
				"needTime" : 0,
				"needYield" : 0,
				"saveState" : 0,
				"restoreState" : 0,
				"isEOF" : 1,
				"invalidates" : 0,
				"keyPattern" : {
					"name" : 1
				},
				"indexName" : "name_1",
				"isMultiKey" : false,
				"multiKeyPaths" : {
					"name" : [ ]
				},
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 2,
				"direction" : "forward",
				"indexBounds" : {  ###使用到的索引
					"name" : [
						"[\"user5\", \"user5\"]"
					]
				},
				"keysExamined" : 1,
				"seeks" : 1,
				"dupsTested" : 0,
				"dupsDropped" : 0,
				"seenInvalidated" : 0
			}
		}
	},
	"serverInfo" : {
		"host" : "localhost",
		"port" : 27017,
		"version" : "3.6.4",
		"gitVersion" : "d0181a711f7e7f39e60b5aeb1dc7097bf6ae5856"
	},
	"ok" : 1
}
>

Stage狀態分析

stage 描述
COLLSCAN 全表掃描
IXSCAN 掃描索引
FETCH 根據索引去檢索指定document
SHARD_MERGE 將各個分片返回數據進行merge
SORT 代表在內存中進行了排序
LIMIT 使用limit限制返回數
SKIP 使用skip進行跳過
IDHACK 針對_id進行查詢
SHARDING_FILTER 經過mongos對分片數據進行查詢
COUNT 利用db.coll.explain().count()之類進行count運算
COUNTSCAN count不使用Index進行count時的stage返回
COUNT_SCAN count使用了Index進行count時的stage返回
SUBPLA 未使用到索引的$or查詢的stage返回
TEXT 使用全文索引進行查詢時候的stage返回
PROJECTION 限定返回字段時候stage的返回

2.profile

MongoDB Database Profiler 是一種慢查詢日誌功能,能夠做爲咱們優化數據庫的依據。

開啓Profiling功能:

《1.》方法一:啓動時,加上--profle=級別便可。

《2.》方法二:在客戶端調用db.setProfilingLevel(級別)命令來實時配置。

Profiler信息保存在system.profile中。咱們能夠經過db.getProfilingLevel()命令來獲取當前的Profile級別。

profile的級別能夠取0,1,2三個值,他們的表示是:

0-不開啓【默認值】

1-記錄慢命令(默認爲>100ms)

2-記錄全部命令

> db.getProfilingLevel();
0
> db.setProfilingLevel(1);
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
> db.getProfilingLevel();
1

Profile在級別爲1時會記錄慢命令,上面的默認值爲100ms,有默認就有設置,其設置方法和級別的方法以下:

《1.》方法一:經過添加--slowms啓動參數設置。

《2.》方法二:db.setProfilingLevel(參數1,參數2)時,加上第二個參數!(貌似此方法很差用!!)

3.優化方案

優化方案1:建立索引

在查詢條件的字段上,或者排序條件的字段上建立索引,能夠顯著提升執行效率。

db.c1.ensureIndex({name:1});

 

優化方案2:限定返回結果條數

使用limit()限定返回結果集的大小,能夠減小database server的資源消耗,能夠減小網絡傳輸的數據量。

db.c1.find().sort({age:-1}).limit(3);

 

優化方案3:查詢使用到的字段,不查詢全部的字段

db.c1.find({},{name:1,age:1}).sort({age:1}).skip(3).limit(2);

 

優化方案4:採用cappedcollection

capped Collections比普通的Collections的讀寫效率高

 

優化方案5:採用Profiling

Profling功能確定會影響效率的,可是不太嚴重,緣由是它使用的是system.profile來記錄,system.profile是一個capped collection。這種collection在操做上有一些限制和特色,可是效率高!

 

3、性能監控

經過對數據庫的性能監控,可以更好的瞭解數據庫的工做狀態,從而進行優化。

Mongoreplay

MongoDB 3.4 引入 mongoreplay 工具,可用於監控並記錄 mongod 上執行的命令並 replay 到另外一個 mongod 實例上,該工具可用於代替 mongosniff。

mongosniff【此工具能夠從底層監控到底有那些命令發送個體MongoDB去執行。

它是實時動態監視的,須要打開另外一個客戶端進行命令操做。能夠將這些數據輸出到一個日誌文件中,那麼久能夠保留下全部數據庫操做的歷史記錄,對於後期的性能分析和安全審計等工做將是一個巨大的貢獻。】

詳細參考:https://bbs.huaweicloud.com/blogs/ac80aa383b9d11e89fc57ca23e93a89f

Mongostat

此工具能夠快速的查看某組運行中的MongoDB實例的統計信息,也須要在打開一個客戶端進行命令操做:

它會間隔固定時間獲取mongodb的當前運行狀態,並輸出。若是你發現數據庫忽然變慢或有其餘問題的話,你第一手的操做就是考慮採用mongostat來查看mongo的狀態。

[root@localhost bin]# /usr/local/mongodb/bin/mongostat
insert query update delete getmore command dirty used flushes vsize   res qrw arw net_in net_out conn                time
    *0    *0     *0     *0       0     2|0  0.0% 0.1%       0 1020M 86.0M 0|0 1|0   158b   59.1k    2 May 27 03:22:59.566
    *0    *0     *0     *0       0     1|0  0.0% 0.1%       0 1020M 86.0M 0|0 1|0   157b   58.8k    2 May 27 03:23:00.566
    *0    *0     *0     *0       0     1|0  0.0% 0.1%       0 1020M 86.0M 0|0 1|0   157b   58.7k    2 May 27 03:23:01.569
    *0    *0     *0     *0       0     1|0  0.0% 0.1%       0 1020M 86.0M 0|0 1|0   157b   58.8k    2 May 27 03:23:02.570

Mongotop

mongotop也是mongodb下的一個內置工具,mongotop提供了一個方法,用來跟蹤一個MongoDB的實例,查看哪些大量的時間花費在讀取和寫入數據。 mongotop提供每一個集合的水平的統計數據。默認狀況下,mongotop返回值的每一秒。

若是每10s返回一次能夠用> # /usr/local/mongodb/bin/mongotop 10

相關文章
相關標籤/搜索