MongoDB系列四(索引).

来源:https://www.cnblogs.com/jmcui/archive/2018/04/10/8757299.html
-Advertisement-
Play Games

一、索引簡介 再來老生常談一番,什麼是索引呢?資料庫索引與書籍的索引類似。有了索引就不需要翻整本書,資料庫可以直接在索引中查找,在索引中找到條目以後,就可以直接跳轉到目標文檔的位置,這能使查找速度提高幾個數量級。 然而,使用索引是有代價的:對於添加的每一個索引,每次寫操作(插入、更新、刪除)都將耗費 ...


一、索引簡介

    再來老生常談一番,什麼是索引呢?資料庫索引與書籍的索引類似。有了索引就不需要翻整本書,資料庫可以直接在索引中查找,在索引中找到條目以後,就可以直接跳轉到目標文檔的位置,這能使查找速度提高幾個數量級。

    然而,使用索引是有代價的:對於添加的每一個索引,每次寫操作(插入、更新、刪除)都將耗費更多的時間。這是因為,當數據發生變動時,MongoDB不僅要更新文檔,還要更新集合上的所有索引。因此,MongoDB限制每個集合上最多只能有64個索引。通常,在一個特定的集合上,不應該擁有兩個以上的索引。於是,挑選合適的欄位建立索引非常重要。

  • 索引基數

基數(cardinality)就是集合中某個欄位擁有不同值的數量。比如 gender 欄位,基數一般就男女 2個而已;而像 mobile 這樣的欄位,基數就會特別大。

通常來講,一個欄位的基數越高,這個欄位上的索引就越有用。這是因為索引能夠迅速將搜索範圍縮小到一個比較小的結果集。對於低基數的欄位,索引通常無法排除掉大量可能的匹配。假設我們在"gender"上有一個索引,需要查找名為Susan的女性用戶。通過這個索引,只能將搜索空間縮小到大約50%。

tips在關係型資料庫中類似 gender 這樣的欄位可以使用點陣圖索引。

  • 索引原理淺析

我們以一個索引 {"age" : 1"username" : 1} 來看看索引在MongoDB 中是如何存儲的,大致是這個樣子:

每一個索引條目都包含一個"age"欄位 和 "username"欄位,並且指向文檔在磁碟中的存儲位置。註意,這裡的 age 嚴格的按照升序排序,並且相同的 age 對應的 username 也嚴格的按照升序排序。

來看個例子 :db.users.find({"age" : 21}).sort({"username" : -1})

這個索引對於這個查詢來說是非常高效的,因為它可以馬上定位到 age = 21 的位置,並且age = 21 中的 username 已經是排序好的。

tips排序方向並不重要:MongoDB可以在任意方向上對索引進行遍歷。
tips查詢中的欄位順序無關緊要,MongoDB 會自動找出可以使用索引的欄位,而無視查詢的欄位順序。

  • $操作符如何使用索引

有一些查詢完全無法使用索引,也有一些查詢能夠比其他查詢更高效地使用索引。

$where:無法使用索引。
$nin:無法使用索引。
$exists:無法使用索引。因為在索引中,不存在的欄位和null欄位的存儲方式是一樣的,查詢必須遍歷每一個文檔檢查這個值是否真的為null還是根本不存在。
$ne:可以使用索引,但並不是很高效。因為必須遍歷整個索引條目才能找到結果的文檔。
$not:能夠使用索引,但通常不知道如何使用索引,從而退化成全表掃描。
$or:能夠使用索引,但是$or 查詢會將 or 的條件拆分成多個獨立的查詢,然後再將結果合併在一起。這是很低效的,不建議用。建議用 $in 取代 $or 。

設計多鍵索引的時候要記得,要把基數大的欄位放在索引的前面,因為這樣能更快縮小查詢的範圍。

二、索引類型

  • 複合(組合)索引

複合索引就是一個建立在多個欄位上的索引。
如果查詢中有多個排序方向或者查詢條件中有多個鍵,複合索引就非常有效。

db.userInfo.ensureIndex({"age":1,"age":1}) 

進行多鍵排序時,索引的方向尤為重要。儘量做到多鍵排序的方向和複合索引的方向是一致的,因為這能很大的避免在記憶體中進行排序的運算。
tips相互反轉(在每個方向上都乘以-1)的索引是等價的:{"age" : 1, "user name" : -1}適用的查詢與{"age" : -1, "username" : 1}是完全一樣的。

複合索引具有雙重功能,而且對不同的查詢可以表現為不同的索引。如果有一個{"age" :1, "username" : 1}索引,"age"欄位會被自動排序,就好像有一個{"age" : 1}索引一樣。因此,這個複合索引可以當作{"age" : 1}索引一樣使用。

  • 唯一索引

唯一索引可以確保集合的每一個文檔的指定鍵都有唯一值。我們熟悉的 "_id" 索引就是一個唯一索引(但它不能被除,而其他唯一索引是可以除的)。

db.users.ensureIndex({"username" : 1}, {"unique" : true})

定義了唯一索引後,這個鍵就不允許插入重覆的值了,否則會拋異常。
tipsA 欄位不存在 和 A 欄位為 null 是互斥的!

在已有的集合上創建唯一索引可能會報錯,因為集合中可能已經有重覆的值了。在極少數情況下,可能希望直接刪除重覆的值。創建索引時使用"dropDups"選項,如果遇到重覆的值,第一個會被保留,之後的重覆文檔都會被刪除。

db.users.ensureIndex({"username" : 1}, {"unique" : true, "dropDups" : true})

  • 稀疏索引

在有些情況下,你可能希望唯一索引只對包含相應鍵的文檔生效。如果有一個可能存在也可能不存在的欄位,但是當它存在時,它必須是唯一的,這時就可以將unique和sparse選項組合在一起使用,創建唯一稀疏索引。註意:MongoDB中的稀疏索引(sparse index)與關係型資料庫中的稀疏索引是完全不同的概念。基本上來說,MongoDB中的稀疏索引只是不需要將每個文檔都作為索引條目。並且,稀疏索引並不一定是唯一的。

db.ensureIndex({"email" : 1}, {"unique" : true, "sparse" : true})

當某個查詢使用了稀疏索引,就不會返回不包含這個欄位的文檔。因為稀疏索引並沒有把每個文檔都作為索引條目。

  • 覆蓋索引

如果你的查詢只需要查找索引中包含的欄位,那就根本沒必要獲取實際的文檔。當一個索引包含用戶請求的所有欄位,可以認為這個索引覆蓋了本次查詢。所以,儘可能使用投射篩選返回的欄位,比如 {"_id":0,"age":1} 等,來實現覆蓋索引。

三、索引管理

  • 新建索引

普通索引

db.userInfo.ensureIndex({"name":1},{"name","MyIndex"})
"1" 表示按照name進行升序,"-1" 表示按照name進行降序。
預設的索引以 key1_1_key2_-1 這樣的方式命名,可以手動指定索引的名字,如上。

對象索引

可以對整個對象建立索引,或者對對象的某個元素使用索引。

db.users.ensureIndex({"loc" : 1})
只有在進行與對象欄位順序完全匹配的子文檔查詢時(比如db.users.find({"loc" :{"ip" : "123.456.789.000", "city" : "Shelbyville", "state" :"NY"}}})),查詢優化器才會使用"loc"上的索引。

db.users.ensureIndex({"loc.city" : 1})
有涉及到對象city的查詢都會使用這個索引。

數組索引

 對數組建立索引,實際上是對數組的每個元素建立一個索引條目。比如一個文檔中的數組欄位有20個元素,那麼該文檔就擁有了20個索引條目!所以對數組欄位的索引建立要慎重。

  • 刪除索引

db.userInfo.dropIndexes("name_1")
刪除指定索引

db.userInfo.dropIndexes()
刪除除了_id 以外的所有索引

  • 操作索引

獲取當前索引列表:db.userInfo.getIndexes()

hint 暴力選擇某種索引:db.userInfo.find({name:'zhangsan',birthday:'1989-3-2'}).hint({"name":1,"birthday":1})

強制使用全表掃描:db.userInfo.find({"birthday" : {"$lt" :"1989-3-2"}}).hint({"$natural" : 1})

索引分析函數explain:MongoDB 3.0前 和 MongoDB 3.0後存在很大的差異,這裡只簡單說明下,如果想詳細瞭解的話,可以關註該作者的文章:

MongoDB 3.0 前:db.driverLocation.find({"areaCode":"350203"}).explain()

cursor:表掃描方式 (basicCursor:順序查找)
nscanned:瀏覽了多少文檔
n:最終返回了幾個文檔
millis:總共耗時了多少毫秒
scanAndOrder:是否必須在記憶體中對數據進行排序

MongoDB 3.0 後:db.driverLocation.find({"areaCode":"350203"}).explain("executionStats")

executionTimeMillis:該query的整體查詢時間
nReturned:查詢返回的條目
totalKeysExamined:索引掃描條目
totalDocsExamined:文檔掃描條目 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • LCOW containers can now be run next to Windows containers.Use '--platform=linux' in Windows container mode to run Linux images.This is an experimental ...
  • 1.在任務欄右擊-任務管理器 2. ...
  • 1、首先編譯安裝nginx(不多說) 2、開始安裝openresty cd /usr/local/src wget https://openresty.org/download/openresty-1.11.2.2.tar.gz tar xf openresty-1.11.2.2.tar.gz cd ...
  • 1.下載jdk1.7 百度雲鏈接: https://pan.baidu.com/s/15vXLO2eV18eVvmt-R5jGnQ 密碼: 1gd6 2.解壓壓縮包 通過終端在/usr/local下新建java文件夾, [root@localhost ~]# mkdir/usr/local/java ...
  • 1、功能上的區別 mv:用戶可以使用該命令為文件或目錄重命名或將文件由一個目錄移入另一個目錄中。 cp: 該命令的功能是將給出的文件或目錄拷貝到另一文件或目錄中。 2、從inode角度來區分 mv:會將存儲於indoe索引節點上的文件元信息也移動到新文件中。 cp : 只會複製文件數據,不會複製in ...
  • 1、安裝Python包管理工具(easy_install) wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py -O - | sudo python 2、安裝supervisor easy_install supervi ...
  • 本文內容: 完整語法 去重選項 欄位別名 數據源 where group by having order by limit 首發日期:2018-04-11 完整語法: select 去重選項 欄位列表 [as 欄位別名] from 數據源 [where子句] [group by 子句] [havin... ...
  • 1.PL/SQL PL/SQL是Oracle對 ql語言的過程化擴展,指在 SQL 命令語言中增加了過程處理語句,使SQL語言具有過程處理能力。把 SQL 語言的數據操縱能 力與過程語言的數據處理能力結合起來,使得 PLSQL 面向過程但比過程語言簡單、高效、靈活和實用。 基本語法結構: [decl ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...