【資料庫寶典】 MongoDB - 進階索引

閱讀時間約 12 分鐘

MongoDB - 索引類型

本篇主要是介紹MongoDB有哪些進階的索引, 了解原理及功能後, 在應用上才能規劃出更有效率的索引, 而主要會談到以下五個索引類型:
  • 複合索引。
  • 部份索引。
  • 多鍵索引。
  • 全文索引。
  • TTL索引。
進入到索引類型之前先提醒一下,一個集合的索引數不能超過64個。

複合索引

限制: 最多只能31個欄位做一組複合索引。
建立方式:
db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )
// 補充: <type>就是1或-1,代表正序或倒序。
首先我們實際來建立一組索引,叫做「人員分數查詢」專用的索引。
db.collection.createIndex({ userid: 1, score: -1}, {name: "人員分數查詢專用索引"})
接著建立幾個樣本資料:
[
{
"userid": "aa1",
"score": 45
},
{
"userid": "ca2",
"score": 55
},
{
"userid": "ca2",
"score": 75
},
{
"userid": "ca2",
"score": 30
},
{
"userid": "nb1",
"score": 30
},
{
"userid": "xyz",
"score": 90
}
]

案例一: 查詢條件發揮複合索引效用。

接著我們來做個查詢分析,分析我們的條件是否在索引之下發揮最大效用。
db.getCollection('test').find({"userid": "ca2", "score": 30}).explain("executionStats")
我們可以發現到Mongo選出來的最佳查詢計畫stage是FETCH,這個我們可以理解為透過索引直接找到文本,而inputStage代表著我們先針對userid, score這兩個索引做掃描,關於查詢分析這邊先不探討,會另外開一篇專門介紹。
  • COLLSCAN:全表掃描。
  • IXSCAN:索引掃描。
  • FETCH: 根據索引到指定的document。
上述結果成功發揮索引效用。

案例二: 查詢條件未能發揮效用

假設今天只找分數不找人員
db.getCollection('test').find({"score": 30}).explain("executionStats")
我們可以發現到Mongo分析出來的查詢計畫是全局掃描,也就是未能發揮索引效用,因此索引建立的順序是有意義的,需要根據需求來進行索引設計。
適用場景: 查詢欄位不只一個,且複合索引的欄位符合建立索引的順序,才能發揮最大的效用*。*

部分索引

我們不想針對該欄位全部的value都進行索引,就可以使用這種索引方式,舉例來說,我們只想對age > 25的值進行索引,建立方式如下:
db.persons.createIndex({country:1},{partialFilterExpression: {age: {$gt:25}}})
  • 其實就是帶有過濾條件的索引,大數據的應用確實應該分析及規劃這個部分。
  • 滿足查詢條件在查詢時才能發揮索引效用,假設我們條件改為age >= 25,那麼Mongo的查詢計畫就會給出全局掃描的選項。

多鍵索引

其實就是對嵌套的文檔做索引。

全文索引

  • 目前不支援中文。
  • 會以空白隔開的方式來建立索引。
{
"id": "1",
"post_text": "enjoy the mongodb articles on Runoob",
}db.posts.ensureIndex({post_text:"text"})# 索引示意: 會以term做為索引的key來記載出現的位置...。
# enjoy => [1, 2...]
# the => [1...]
# ...
  • 搜尋也是有一些強大功能的, 如下:
// 簡單的查詢mongodb這個詞。
db.posts.find( { $text: { $search: "mongodb" } } );
// 查詢mongodb或articles這兩個詞。
db.posts.find({$text:{$search:"mongodb articles"}});
// 查詢包含mongodb但不包含elasticsearch的文本, 會用`-`來表示不包含。
db.posts.find({$text:{$search:"mongodb -elasticsearch"}});
// 查詢「mongodb articles」這個片語的文本。
db.posts.find({$text:{$search:"\\"mongodb articles\\""}})

TTL索引

TTL索引常常用在log應用, 假設使用者操作的歷程我們只想要保留半年, 則我們可以針對Collection進行TTL索引的建立, 而Mongo背景服務就會定時幫我們清除過期的資料, 但是使用上有幾個特別要注意的地方如下:

清除的型態是什麼?

  • 只能是BSON的Date型態才能被清除。
  • 如果用整數的Timestamp會沒有作用。

如果Collection本身已經是Capped的話, 我們又設定TTL會發生什麼事情呢?

會發生以下的錯誤訊息, 由於我們基礎篇有提到Capped Collection如果要刪除Document只能對整個Collection進行刪除, 故我們如果需求上已經對某個Collection規劃為Capped時, 就不要在用TTL索引了!!!
2020-11-23T03:36:21.405+0000 E INDEX    [TTLMonitor] Error processing ttl index: { v: 2, key: { creationTime: 1 }, name: "expiredIdx", ns: "qa.qm_event_log", expireAfterSeconds: 1, background: true } -- 10089 cannot remove from a capped collection

如何更新TTL失效時間?

  • 已建立的索引, 如果動態更改TTL參數會發生錯誤如下。
db.createIndex(...)
Index with name: expiredIdx already exists with different options
  • 使用DB Command「collMod」來更新。
// Update the index with 120 seconds expiration threshold
db.runCommand({
collMod: 'ttldemo',
index: {keyPattern: {created_at: 1}, expireAfterSeconds: 120}
});
  • 刪除重建。

刪除重建後,之前的Documents會套用嗎?

  • 我們先預設一小時後失效。
db.test.createIndex({created_at: 1}, {expireAfterSeconds: 600});
  • 建立一筆Document時間為now。
db.test.insert({
created_at: new Date()
})
  • 此時我們先確保背景服務不會去刪除我們的Document
2020-11-23T04:22:21.437+0000 D INDEX    [TTLMonitor] ns: qa.test key: { created_at: 1.0 } name: created_at_1
2020-11-23T04:22:21.437+0000 D INDEX [TTLMonitor] deleted: 0
  • 刪除重建索引為1秒鐘後失效。
db.test.dropIndex("created_at_1");
db.test.createIndex({created_at: 1}, {expireAfterSeconds: 1});
  • 再建立一筆Document時間為now。
db.test.insert({
created_at: new Date()
})
  • 此時已有兩筆, 我們來看看是否兩筆都會套用? 答案是會的!
2020-11-23T04:25:21.439+0000 D INDEX    [TTLMonitor] ns: qa.test key: { created_at: 1.0 } name: created_at_1
2020-11-23T04:25:21.439+0000 D INDEX [TTLMonitor] deleted: 2

如何監控TTL是否執行?

預設的MongoDB不會將TTL訊息印出, 如果我們打算讓該Log訊息印出, 則可以透過以下的配置來完成。
db.setLogLevel(1, "index");
印出訊息如下, Log會告知我們哪個時間點清除了哪些資料:
2020-11-23T03:40:21.407+0000 D INDEX    [TTLMonitor] ns: admin.logsfilter key: { expiredAt: 1 } name: expiredAt_1
2020-11-23T03:40:21.407+0000 D INDEX [TTLMonitor] deleted: 0
2020-11-23T03:40:21.407+0000 D INDEX [TTLMonitor] ns: qa.error_log key: { creationTime: 1 } name: expiredIdx
2020-11-23T03:40:21.407+0000 D INDEX [TTLMonitor] deleted: 0

MongoDB背景多久執行一次TTL清除動作?

  • 預設60秒執行一次清除動作。
db.adminCommand({getParameter:1, ttlMonitorSleepSecs: 1});{
"ttlMonitorSleepSecs" : 60,
"ok" : 1.0
}
  • 如何更改執行間隔(盡量不要太短, TTL索引過多將造成CPU負荷)。
> db.adminCommand({setParameter:1, ttlMonitorSleepSecs: 3600}); // 1 minute
{ "was" : 60, "ok" : 1 }

TTL刪除了多少Document

db.serverStatus().metrics.ttl
{
"deletedDocuments" : NumberLong(13533),
"passes" : NumberLong(20374)
}

常用的指令

# 查看collection佔用索引的容量
db.collection.totalIndexSize()
為什麼會看到廣告
114會員
256內容數
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
留言0
查看全部
發表第一個留言支持創作者!
阿Han的沙龍 的其他內容
主要是收攏documents的容器, 可以支援各種不同結構的document。 不能為空字串。 不能以system開頭, 這是系統集合保留的前綴。 超過配置大小, 新增時當超過配置限額時, 會先從最早的document刪除後再append新的document。 更新時不能超過size限制。 不能刪除
大數據的時代,如何有效率的搜尋來找到我們要的答案?這時候就要透過一些資訊檢索的技術來幫我們提升效率了,而本篇會介紹索引的基本概念以及為什麼演化至倒排索引,為我們帶來了哪些好處? 什麼是索引? 那什麼又是倒排索引? 能解決什麼問題呢? 為什麼更快更精準? 結語
主要是收攏documents的容器, 可以支援各種不同結構的document。 不能為空字串。 不能以system開頭, 這是系統集合保留的前綴。 超過配置大小, 新增時當超過配置限額時, 會先從最早的document刪除後再append新的document。 更新時不能超過size限制。 不能刪除
大數據的時代,如何有效率的搜尋來找到我們要的答案?這時候就要透過一些資訊檢索的技術來幫我們提升效率了,而本篇會介紹索引的基本概念以及為什麼演化至倒排索引,為我們帶來了哪些好處? 什麼是索引? 那什麼又是倒排索引? 能解決什麼問題呢? 為什麼更快更精準? 結語
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
每日自動檢查資料庫運作所產生的訊息,若發現有錯誤,自動寄出警告信給擔當人員
Thumbnail
Notion內建的日期欄位,可以調整顯示英文的日期格式 但是若想要顯示台灣的民國、中文的星期、或是日本的平成昭和幾年要怎麼做呢? 透過Notion formula只要填好日期,就可自動呈現出台灣民國年度、台灣星期、年齡計算、距離今年過了幾年/是幾年後等等,各種格式的函數Notion模板免費索取!
※什麼是資料 : 說明: 「資料」(information/data) 是網路應用程式的核心。 使用者分享的照片、電商販賣的產品,或是搜索引擎提供的餐廳評價都是資料。 主要特徵: 生活中任何基本的事實 (fact) 或是值 (value) 都可以被稱為資料。例如:你的名字、你的生日。 因
Thumbnail
【生活話題】要健康VS要隱私!健保資料庫違憲? 本所許惠菁律師主持央廣【生活有辦法】,憲法法庭討論「運用健保資料庫的個人健康資料做醫學研究」是否有違憲。
Thumbnail
最近接獲一個任務,該任務的目標是替一個即將進入正式部署階段的系統,導入一個 database migration tool,以下是此任務整個思考決策的邏輯以及正式進行時技術上比較值得和大家分享的小細節。 系統背景 資料庫的設計方式,目前常見會有兩種方向,code first 以及 database
Thumbnail
UNIX 在設計時,用 32 位元為基礎設計,Timestamp (time_t 結構) 順理成章也是 32 位元 (signed int32),從 1970 年開始算,導致它能記錄的時間在 2038 年會溢位變負數。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
每日自動檢查資料庫運作所產生的訊息,若發現有錯誤,自動寄出警告信給擔當人員
Thumbnail
Notion內建的日期欄位,可以調整顯示英文的日期格式 但是若想要顯示台灣的民國、中文的星期、或是日本的平成昭和幾年要怎麼做呢? 透過Notion formula只要填好日期,就可自動呈現出台灣民國年度、台灣星期、年齡計算、距離今年過了幾年/是幾年後等等,各種格式的函數Notion模板免費索取!
※什麼是資料 : 說明: 「資料」(information/data) 是網路應用程式的核心。 使用者分享的照片、電商販賣的產品,或是搜索引擎提供的餐廳評價都是資料。 主要特徵: 生活中任何基本的事實 (fact) 或是值 (value) 都可以被稱為資料。例如:你的名字、你的生日。 因
Thumbnail
【生活話題】要健康VS要隱私!健保資料庫違憲? 本所許惠菁律師主持央廣【生活有辦法】,憲法法庭討論「運用健保資料庫的個人健康資料做醫學研究」是否有違憲。
Thumbnail
最近接獲一個任務,該任務的目標是替一個即將進入正式部署階段的系統,導入一個 database migration tool,以下是此任務整個思考決策的邏輯以及正式進行時技術上比較值得和大家分享的小細節。 系統背景 資料庫的設計方式,目前常見會有兩種方向,code first 以及 database
Thumbnail
UNIX 在設計時,用 32 位元為基礎設計,Timestamp (time_t 結構) 順理成章也是 32 位元 (signed int32),從 1970 年開始算,導致它能記錄的時間在 2038 年會溢位變負數。