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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...