您好,登錄后才能下訂單哦!
索引,使用索引可快速訪問數據庫表中的特定信息。索引是對數據庫表中一列或多列的值進行排序的一種結構,例如 employee 表的姓名(name)列。如果要按姓查找特定職員,與必須搜索表中的所有行相比,索引會幫助您更快地獲得該信息。
索引的優點:
不需要做全表掃描,只需要掃描索引索引只存儲了這個表的數據的一小部分,這小部分可以幫我們實現快速查詢,因此掃描的時候只掃描這一小部分即可,如果將這小部分裝載入內存中的話,速度會更快
·大大減少了服務器需要掃描的數據量
·索引可以幫助服務器避免排序或使用臨時表
·索引可以將隨機I/O轉換為順序I/O
索引的缺點:
索引是保存了數據表上的一小部分數據,那么這些數據是需要額外存儲的,毫無疑問如果更新了表中的數據,那么響應的索引數據也要跟著更新,加速了查找操作,但是減少了寫入速度對查找的加速是否有用還是有待評估的,比如我們將一個表中的按年齡實現了索引創建(在年齡上創建了索引)平時大多數操作都是按照名字上去查找的,那么索引則無任何作用,所謂索引必須跟查找建完全匹配才有意義,但我們要知道大多數的查找未必只在有限字段上執行,也就意味著創建索引必須包含多個段,需要看索引是如何去生成的,對于多個條件可以將索引做為組合索引來查找,所以索引的設計是非常有技巧的
索引本身帶來的未必是優勢,如果一張表中索引非常的多的話,可能對于整個系統性能的影響是非常大的,如果一張表的本身非常小只有十幾行,創建索引反而會減慢速度的,因為全表掃描也未必用不了多長時間
但如果表非常大的話,索引則非常有用,如果數據量過大那么索引反而也未必有意義,比如一張表非常大,上T的數據,可以想象一下創建什么樣的索引才可以,所以只能將大表切割成小表,并且分布在不同的物理節點上,對mysql來說叫做分區;對mongodb來講叫shaerd
索引級別:
索引最高級別3星索引
1星:索引國能將相關的記錄放置在一起,大大降低了I/O
2星:索引中數據的存儲順序與查找標準中順序一致(只要設計良好即可)
3星:如果索引中包含查詢中所需要的全部數據(覆蓋索引)
索引的類別:
·順序索引
·散列索引
將索引映射至散列桶中,映射是通過散列函數進行的
評估索引標準:
1、訪問類型(如果做等值比較 散列比較好,如果做范圍查找,那么順序比較好
2、訪問時長(為完成一個訪問,基于索引類型訪問的時間可能不同)
3、插入時長(更新表的話索引本身可能會有很大代價,如果散列索引的話只不過重新執行以下算法即可,但是對于順序索引的話,有可能會移動索引列表后面的索引數據)
4、刪除時長
5、空間開銷
索引類型:
·順序索引:按照聚集索引存放的文件也被稱為索引順序文件,最常見的索引類型,一般來講被索引文件記錄,如果按照順序存放則為索引順序文件,否則為堆文件
·聚集索引:如果某記錄文件中的記錄順序是按照對應的搜索碼(鍵/key)的順序排序的話,被稱為主索引
·非聚集索引:搜索碼中的指定的次序與記錄中的記錄次序不一致
根據索引中是否為每個記錄響應的創建索引項:
·稠密索引 (每個搜索碼值都有一個對應的索引項
·稀疏索引 (并不是每個記錄都有索引項)
·多級索引 (索引指向索引,以此類推,最后的索引指向數據;
索引本身,主索引之外的索引被稱為輔助索引,而只有主索引才能使用稀疏索引,其他所有必需是稠密索引,而輔助索引必須是稠密索引
·B+樹索引:
·Balance Tree 平衡樹索引
·每個葉子節點,從葉子至根的距離是相同的,所以叫做平衡樹
·層次需要根據數據量來動態創建層次
·B+樹是一種順序索引
散列索引則:
通過散列函數,數據庫加載為一次I/O 指針加載數據為2次 I/O。
I/O是占據時間比例是最大值的,索引散列索引的速度在做精確匹配的時候會更快,因為I/O次數要少的多的多,因此散列索引能夠讓我們避免訪問索引結構的。
散列索引的缺點:散列索引還有可能造成偏斜,長久以來可能發有的散列桶有的滿有的空 導致每個節點的負載參差不齊,如果散列函數做的不夠隨機就有可能造成偏斜的情況
所以散列函數需要做到以下幾點:
·分布式隨機
·分布式均勻
散列函數適用的場景:精確值匹配,比如做等值比較: = ,IN(), <=> 等
全文索引:
默認情況下順序索引只能索引字段的前有限個字節,假如字段名是test,test是可以創建存儲文本量非常大,不可能將所有的數據全部存放在索引中,肯定只在其中抽取部分字節,所以查找標準肯定是最左前綴方式,不能包含整個字段,如果想實現全文匹配關鍵字匹配的話,這樣則只能使用全文索引(mysql中只有myisam引擎支持)(innodb的話則可以借助外界的索引工具來實現比如sphinx)
如果必須要實現全文索引,使用sphinx是個不錯的選擇
空間索引:
索引中的數據不能查找,必須使用空間索引函數來獲取相應查找結果
索引的特性:
·全值匹配:
簡單來講,匹配他的用戶名:Name="User12" ,匹配最左前綴:
Name LIKE"User1%"
無效: Name LIKE"%User1%"
·匹配列前綴:與最左前綴一樣(Name LIKE"User1%" 無效: Name LIKE"%User1%") 假如組合索引創建了2個字段:Name,Age 從最左側開始則有效,那么Age > 80 這樣則沒有任何意義,因為查找條件一定必須從最左邊開始的,但是反過來則非常用有:(Age,Name)
匹配范圍值:精確匹配某一列并范圍匹配另外一列 比如name=12并age大于80
只訪問索引的查詢:
假設順序索引是3級,要找到對應的行數據,如果沒有使用覆蓋索引,那么需要幾次I/O:首先查找到根索引. 然后查找下一級索引,如果下一級索引在磁盤上,那么意味著將裝載數據塊,這為1次IO ,再一次索引則又消耗一次IO,再次裝載硬盤數據,則又一次I/O,如果事先根索引沒有被加載,那么至少需要4次I/O才會找到數據
主鍵,唯一鍵 都是順序索引,但是唯一不同的地方是:主鍵是不能重復 不能為空,唯一鍵可以重復可以為空
創建索引:
> db.testcoll.find()
{ "_id" : ObjectId("531fbe8d020f14309ee1410a"), "Name" : "User1","Age" : 1, "Gender" : "M", "preferbook": [ "blue book", "yellow book" ] }
{ "_id" : ObjectId("531fbe8d020f14309ee1410b"), "Name" : "User2","Age" : 2, "Gender" : "M", "preferbook": [ "blue book", "yellow book" ] }
{ "_id" : ObjectId("531fbe8d020f14309ee1410c"), "Name" : "User3","Age" : 3, "Gender" : "M", "preferbook": [ "blue book", "yellow book" ] }
如上所示,我們要在用戶字段名上創建索引,注意的是字段id默認就是索引,而且是主鍵索引,我們在主鍵索引之外創建索引都被稱為輔助索引 ,因為表內大多數都是根據用戶名來查找的,所以希望根據用戶名來查找索引:
使用命令ensureIndex 在Name字段上創建索引
> db.testcoll.ensureIndex({Name:1})
查看索引:
> db.testcoll.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" :"testdb.testcoll",
"name" :"_id_"
},
#第二個索引是在name上創建,是我們自己指定的,如下所示:
{
"v" : 1,
"key" : {
"Name" : 1
},
"ns" :"testdb.testcoll",
"name" :"Name_1"
}
刪除索引:
可以使用dropIndex 將name字段的索引刪除
> db.testcoll.dropIndex({Name:1})
{ "nIndexesWas" : 2, "ok" : 1 }
再次查看其索引
> db.testcoll.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" :"testdb.testcoll",
"name" :"_id_"
}
]
刪除coll所有的索引
> db.testcoll.dropIndex({Name:1})
同時也支持使用唯一索引,我們可以在name這個字段上創建唯一索引,也就意味著用戶名不得出現重復的名字
#唯一索引
> db.testcoll.ensureIndex({Name:1},{unique:true})
#稀疏索引
> db.testcoll.ensureIndex({Name:1},{sparse:true})
MongoDB中所支持的索引類型
對mongodb來講,索引可以創建在collection級別,也可以創建在sub-field中()子collection
完全可以根據自己的需求創建,那么索引可以將隨機IO轉換為順序IO
索引類型:
1、單鍵索引(創建在一個字段上的索引)
2、組合索引(上面提到了)
3、多鍵索引(一個文檔中某個字段的值可以是數組,如果創建在這么個字段上,一個字段上有多個值,則為多鍵索引,(一個值為一個數組))
4、空間索引(只能使用空間索引函數,與mysql一致)
5、文本索引(全文索引)
6、哈希索引
創建哈希索引的話,必須明確說明哈希的格式才可以,如下所示:
>db.testcoll.ensureIndex({Name:"hashed"})
> db.testcoll.dropIndex({Name:"hashed"})
顯示索引是否能用到:
顯示查詢語句是否能真正用到所創建的索引:
> db.testcoll.find({Name: "User19"}).explain()
{
"cursor" : "BtreeCursor Name_1",
"isMultiKey" : false, #是否用到鍵
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1, #掃描了多少個記錄
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false, #掃描后有沒有記錄
"indexOnly" : false, #是否用到索引,是否僅在索引中
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"Name" : [
[
"User19",
"User19"
]
]
},
"server" : "localhost:27017"
}
將索引刪除:
> db.testcoll.find({Name: "User19"}).explain()
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 99, #掃描的對象為全部,意為全表掃描
"nscanned" : 99,
"nscannedObjectsAllPlans" : 99,
"nscannedAllPlans" : 99,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
},
"server" : "localhost:27017"
}
在查詢的時候可以用hint指定使用的索引
> db.testcoll.find({Name: "User19"}).hint({Name:1}).explain()
創建組合索引
> db.testcoll.ensureIndex({Name:1,Age:1},{uniqe:true})
> db.testcoll.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" :"testdb.testcoll",
"name" :"_id_"
},
{
"v" : 1,
"key" : {
"Name" : 1,
"Age" : 1
},
"ns" :"testdb.testcoll",
"name" :"Name_1_Age_1",
"uniqe" : true
}
]
如果不指定則在name:1上查找索引。如下所示:
> db.testcoll.find({Name: "User19"}).explain()
{
"cursor" : "BtreeCursor Name_1_Age_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"Name" : [
[
"User19",
"User19"
]
],
"Age" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "localhost:27017"
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。