MongoDB基礎操作

misakivv發表於2024-04-26

目錄
  • 一、什麼是MongoDB
  • 二、MongoDB 與關係型資料庫對比
  • 三、資料型別
  • 四、部署MongoDB
    • 1、下載二進位制包
    • 2、下載安裝包並解壓
    • 3、建立用於存放資料和日誌的目錄,並修改許可權
    • 4、啟動MongoDB
      • 4.1前臺啟動
      • 4.2後臺啟動
      • 4.3、配置檔案啟動服務
      • 4.4、配置systemd服務
      • 4.5、systemctl啟動MongoDB
    • 5、客戶端配置
    • 6、關閉MongoDB
      • 6.1、前臺啟動
      • 6.2、後臺啟動
      • 6.3、kill命令關閉
      • 6.4、MongoDB函式關閉
  • 五、MongoDB基本操作及增刪改查
    • 1、基本操作
      • 1.1、登入資料庫
      • 1.2、檢視資料庫
      • 1.3、檢視當前正在使用的資料庫
      • 1.4、選擇/建立資料庫
      • 1.5、檢視集合
      • 1.6、建立集合
      • 1.7、刪除集合
      • 1.8、刪除資料庫
    • 2、增刪改查
      • 2.1、插入文件
        • 2.1.1、一次性插入多條資料
      • 2.2、查詢文件
        • 2.2.1、查詢集合內所有的記錄數
      • 2.3、修改文件
      • 2.4、刪除文件
  • 六、MongoDB支援儲存的資料型別
    • 1、數字
    • 2、字串
    • 3、正規表示式
    • 4、陣列
    • 5、日期
    • 6、內嵌文件
  • 七、MongoDB中的索引
    • 1、檢視索引
    • 2、需要索引的查詢場景
      • 2.1、建立有10000個文件的集合
      • 2.2、查詢age200的文件
      • 2.3、新增limit查詢文件
      • 2.4、建立索引
      • 2.5、自定義索引名字
    • 3、檢視索引的大小
    • 4、刪除索引
      • 4.1、按名稱刪除索引
      • 4.2、刪除所有的索引
    • 5、優缺點
      • 5.1、優點:
      • 5.2、缺點:

一、什麼是MongoDB

MongoDB 是一個開源、高效能、無模式的、基於分散式檔案儲存的文件型資料庫,當初的設計就是用於簡化開發和方便擴充套件,是 NoSQL 資料庫產品中的一種。是最像關係型資料庫(MySQL)的非關係型資料庫。

它支援的資料結構非常鬆散,是一種類似於JSON的格式叫BSON(Binary JSON),所以它既可以儲存比較複雜的資料型別,又相當的靈活。

二、MongoDB 與關係型資料庫對比

webp

SQL 術語/概念 MongoDB 術語/概念 解釋說明
database database 資料庫
table collection 資料庫表/集合
row document 資料記錄行/文件
column field 資料欄位/域
index index 索引
table joins 不支援 表連線,MongoDB 不支援
不支援 嵌入文件 MongoDB 透過嵌入式文件來替代多表連線
primary key primary key 主鍵,MongoDB 自動將_id 欄位設定為主鍵

三、資料型別

資料型別 描述 舉例
字串 utf8字串都可以表示為字串型別的資料
物件id 物件id是文件的12位元組的唯一ID
布林值 真或者假:true或者false
陣列 值的集合或者列表都可以表示成陣列
整數 (Int32 Int64 你們就知道有個Int就行了,一般我們用Int32)
null 表示空值或者未定義的物件
undefined 文件中也可以使用未定義型別

四、部署MongoDB

1、下載二進位制包

下載地址

image-20240424165506053

2、下載安裝包並解壓

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.6.tgz
tar xzvf mongodb-linux-x86_64-rhel70-4.4.6.tgz -C /usr/local
cd /usr/local/
ln -s /usr/local/mongodb-linux-x86_64-rhel70-4.4.6 /usr/local/mongodb

3、建立用於存放資料和日誌的目錄,並修改許可權

# 建立存放資料的目錄
mkdir -p /usr/local/mongodb/data/db
# 建立存放日誌的目錄
mkdir -p /usr/local/mongodb/logs
# 建立日誌記錄檔案
touch /usr/local/mongodb/logs/mongodb.log

4、啟動MongoDB

4.1前臺啟動

MongoDB的預設啟動方式為前臺啟動

cd /usr/local/mongodb/

bin/mongod \
--dbpath /usr/local/mongodb/data/db/ \
--logpath /usr/local/mongodb/logs/mongodb.log \
--logappend \
--port 27017 \
--bind_ip 0.0.0.0

引數解釋:

 --dbpath:指定資料檔案存放目錄
 --logpath:指定日誌檔案,注意是指定檔案不是目錄
 --logappend:使用追加的方式記錄日誌
 --port:指定埠,預設為 27017
 --bind_ip:繫結服務 IP,若繫結 127.0.0.1,則只能本機訪問,預設為本機地址

4.2後臺啟動

後臺啟動在命令中新增--fork即可

cd /usr/local/mongodb/

bin/mongod \
--dbpath /usr/local/mongodb/data/db/ \
--logpath /usr/local/mongodb/logs/mongodb.log \
--logappend \
--port 27017 \
--bind_ip 0.0.0.0 \
--fork

4.3、配置檔案啟動服務

bin目錄下增加一個mongodb.conf配置檔案

vim /usr/local/mongodb/bin/mongodb.conf
# 資料檔案存放目錄
dbpath = /usr/local/mongodb/data/db
# 日誌檔案存放目錄
logpath = /usr/local/mongodb/logs/mongodb.log
# 以追加的方式記錄日誌
logappend = true
# 埠預設為 27017
port = 27017
# 對訪問 IP 地址不做限制,預設為本機地址
bind_ip = 0.0.0.0
# 以守護程序的方式啟用,即在後臺執行
fork = true

image-20240424171746978

啟動命令:

bin/mongod -f /usr/local/mongodb/bin/mongodb.conf

image-20240424172044021

4.4、配置systemd服務

vim /usr/lib/systemd/system/mongodb.service

[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target 
[Service] 
Type=forking 
ExecStart=/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/bin/mongodb.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/usr/local/mongodb/bin/mongod --shutdown --config /usr/local/mongodb/bin/mongodb.conf
PrivateTmp=true 
[Install] 
WantedBy=multi-user.target

chmod 754 /usr/lib/systemd/system/mongodb.service

4.5、systemctl啟動MongoDB

systemctl start mongodb

5、客戶端配置

新增環境變數

echo "export PATH=/usr/local/mongodb/bin/:$PATH" >> /etc/profile
source /etc/profile
mongo

6、關閉MongoDB

6.1、前臺啟動

Ctrl + c

6.2、後臺啟動

# 命令啟動方式的關閉
bin/mongod --dbpath /usr/local/mongodb/data/db/ --logpath /usr/local/mongodb/logs/mongodb.log --logappend --port 27017 --bind_ip 0.0.0.0 --fork --shutdown
# 配置檔案啟動方式的關閉
bin/mongod -f /usr/local/mongodb/bin/mongodb.conf --shutdown

6.3、kill命令關閉

不推薦使用

# 檢視 mongodb 執行的程序資訊
ps -ef | grep mongodb
# kill -9 強制關閉
kill -9 pid

6.4、MongoDB函式關閉

# 連線 mongodb
mongo
# 切換 admin 資料庫
use admin
# 執行以下函式(2選1)即可關閉服務
db.shutdownServer()
db.runCommand("shutdown")

五、MongoDB基本操作及增刪改查

1、基本操作

1.1、登入資料庫

mongo

1.2、檢視資料庫

show databases
show dbs

image-20240424183039764

1.3、檢視當前正在使用的資料庫

db

image-20240425115609645

1.4、選擇/建立資料庫

use admin

image-20240425114338328

如果切換到一個沒有的資料庫,那麼會隱式建立這個資料庫。(後期當該資料庫有資料時,系統自動建立)

use admin1

image-20240425114612080

1.5、檢視集合

show collections

image-20240425114752959

1.6、建立集合

db.createCollection('集合名')

image-20240425115030221

1.7、刪除集合

db.集合名.drop()

image-20240425115744209

1.8、刪除資料庫

透過use語法選擇資料
透過db.dropDataBase()刪除資料庫

> use admin1
switched to db admin1
> show collections
c2
> db.dropDatabase()
{ "dropped" : "admin1", "ok" : 1 }
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

image-20240425120604758

2、增刪改查

2.1、插入文件

如果集合存在,那麼直接插入資料。

如果集合不存在,那麼會隱式建立。

db.集合名.insert(JSON資料)
  • 在test1資料庫的c1集合中插入文件,(姓名:張三,年齡:18)
> use test1
switched to db test1
> show collections
> db.createCollection('c1')
{ "ok" : 1 }
> db.c1.insert({name:"張三",age:18})
WriteResult({ "nInserted" : 1 })
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "張三", "age" : 18 }

image-20240425125211753

  • 資料庫和集合不存在都隱式建立
  • 物件的鍵統一不加引號(方便看),但是檢視集合資料時系統會自動加
  • mongodb會給每條資料增加一個全球唯一的_id
2.1.1、一次性插入多條資料
  • 陣列中一個個寫入json資料
> db.c1.insert([{name:"李四",age:20},{name:"王五",age:21},{name:"趙六",age:22}])
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 3,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "張三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "趙六", "age" : 22 }

image-20240425125249398

  • 寫for迴圈插入資料
> for (var i=1;i<=10;i++) {db.c1.insert({name:"a"+i , age: i}) }
WriteResult({ "nInserted" : 1 })
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "張三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "趙六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1", "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2", "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3", "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4", "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5", "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6", "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425125400607

2.2、查詢文件

db.集合名.find(條件[,查詢的列])
條件 寫法
查詢所有的資料 {}或者不寫
查詢age=6的資料
既要age=6又要性別=男
查詢的列(可選引數) 寫法
查詢全部列(欄位) 不寫
只顯示age列(欄位)
除了age列(欄位)都顯示

其他語法

db.集合名.find({
            鍵:{運算子:值}
            })
運算子 作用
$gt 大於
$gte 大於等於
$lt 小於
$lte 小於等於
$ne 不等於
$in in
$nin not in
  • 檢視所有資料
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "張三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "趙六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1", "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2", "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3", "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4", "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5", "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6", "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425125449664

  • 只看name列
> db.c1.find({},{name:1})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "張三" }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四" }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五" }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "趙六" }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1" }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2" }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3" }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4" }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5" }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6" }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7" }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8" }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9" }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10" }

image-20240425125526995

  • 檢視除了name列
> db.c1.find({},{name:0})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "age" : 10 }

image-20240425125554132

  • 查詢age大於6的資料
> db.c1.find({age:{$gt:6}})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "張三", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "趙六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425125634325

  • 查詢年齡為7歲、10歲、18歲的資料
> db.c1.find({age:{$in:[7,10,18]}})
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "張三", "age" : 18 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425142853007

2.2.1、查詢集合內所有的記錄數
db.集合名.count()

image-20240425205417337

2.3、修改文件

db.集合名.update(
  <filter>,          // 查詢條件(篩選待更新的文件)
  <update>,          // 更新操作定義(如何修改文件)
  {
    upsert: <boolean>,  // 可選,如果無匹配文件則插入,預設為 false
    multi: <boolean>,   // 可選,是否更新所有匹配的文件,預設為 false(僅更新第一條)
    collation: <object>, // 可選,指定比較選項(如大小寫敏感等)
    arrayFilters: <array>, // 可選,用於處理巢狀陣列中的條件匹配
    hint: <string|document>, // 可選,提供索引來指導查詢
    writeConcern: <document>, // 可選,指定寫關注級別
    let: <object> // 可選,用於與聚合管道更新相關的變數定義
  }
)
  • {name:"張三"}修改為{name:"zhangsan"}
> db.c1.update({name:"張三"},{$set:{name:"zhangsan"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.c1.find()
{ "_id" : ObjectId("6629dc959117871a1f5ab723"), "name" : "zhangsan", "age" : 18 }
{ "_id" : ObjectId("6629de189117871a1f5ab724"), "name" : "李四", "age" : 20 }
{ "_id" : ObjectId("6629de189117871a1f5ab725"), "name" : "王五", "age" : 21 }
{ "_id" : ObjectId("6629de189117871a1f5ab726"), "name" : "趙六", "age" : 22 }
{ "_id" : ObjectId("6629def99117871a1f5ab727"), "name" : "a1", "age" : 1 }
{ "_id" : ObjectId("6629def99117871a1f5ab728"), "name" : "a2", "age" : 2 }
{ "_id" : ObjectId("6629def99117871a1f5ab729"), "name" : "a3", "age" : 3 }
{ "_id" : ObjectId("6629def99117871a1f5ab72a"), "name" : "a4", "age" : 4 }
{ "_id" : ObjectId("6629def99117871a1f5ab72b"), "name" : "a5", "age" : 5 }
{ "_id" : ObjectId("6629def99117871a1f5ab72c"), "name" : "a6", "age" : 6 }
{ "_id" : ObjectId("6629def99117871a1f5ab72d"), "name" : "a7", "age" : 7 }
{ "_id" : ObjectId("6629def99117871a1f5ab72e"), "name" : "a8", "age" : 8 }
{ "_id" : ObjectId("6629def99117871a1f5ab72f"), "name" : "a9", "age" : 9 }
{ "_id" : ObjectId("6629def99117871a1f5ab730"), "name" : "a10", "age" : 10 }

image-20240425184009386

  • {name:"李四"}的年齡加/減5

年齡加5

db.c1.update({name:"李四"},{$inc:{age:5}})

image-20240425184419154

年齡減5

db.c1.update({name:"李四"},{$inc:{age:-5}})

image-20240425184616300

2.4、刪除文件

db.集合名.remove(條件[,是否刪除一條])
  • 刪除一條資料

    • db.c1.remove({},true)
      

      預設刪除的第一條資料

      image-20240425204653851

    • db.c1.remove({name:"李四"})
      

      刪除指定資料

      image-20240425204856853

六、MongoDB支援儲存的資料型別

1、數字

  • shell預設使用64位浮點型數值
db.b1.insert({x:3.1415926})
db.b1.insert({x:3})

image-20240425213512686

  • 整型值,可以用NumberInt或者NumberLong表示
db.b1.insert({x:NumberInt(10)})
db.b1.insert({x:NumberLong(12)})

image-20240425213843340

2、字串

db.b1.insert({x:"hello MongoDB!"})

image-20240425214353152

3、正規表示式

查詢所有keyx,valuehello開頭的文件且不區分大小寫

db.b1.find({x:/^(hello).(.[a-zA-Z0-9])+/i})

image-20240425214936289

4、陣列

陣列中的資料型別可以是多種多樣的

db.b1.insert({x:[1,2,3,4,new Date()]})

image-20240425215940415

5、日期

db.b1.insert({x:new Date()})

image-20240425220308105

6、內嵌文件

一個文件也可以作為另一個文件的value

db.b1.insert({name:"三國演義",author:{name:"羅貫中",age:70}})

image-20240425221008151

七、MongoDB中的索引

1、檢視索引

預設情況下,集合中的_id欄位就是索引,我們可以透過getIndexes()方法來檢視一個集合中的索引:

db.b1.getIndexes()

image-20240425222309926

  1. v: 表示索引版本。在這個例子中,值為 2,表示這是一個版本 2 的索引。索引版本通常由 MongoDB 內部管理,使用者通常不需要直接關心。
  2. key: 描述了索引的鍵(即排序依據)。鍵是一個物件,鍵名為欄位名,鍵值為排序方向。在給出的例子中,{ "_id" : 1 } 表示索引基於欄位 _id,且按升序(1)排序。在 MongoDB 中,每個集合都預設有一個名為 _id 的主鍵索引,它是唯一的,並且總是按升序排列。
  3. name: 指定索引的名稱。這裡為 "name" : "_id_",表示這是一個針對 _id 欄位的索引,其名稱預設為 _id_。在 MongoDB 中,主鍵索引的名稱通常是固定的,即 _id_

2、需要索引的查詢場景

2.1、建立有10000個文件的集合

for (var i=1;i<=10000;i++) {db.q1.insert({name:"test"+i , age: i})}
db.q1.count()

image-20240426082844602

2.2、查詢age200的文件

db.q1.find({age:200})

image-20240425230647795

這種查詢預設情況下會做全表掃描,可以用explain()來檢視一下查詢計劃

db.q1.find({age:200}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test3.q1",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 200
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "age" : {
                                        "$eq" : 200
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 2,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 10000,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "age" : {
                                        "$eq" : 200
                                }
                        },
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 10002,
                        "advanced" : 1,
                        "needTime" : 10000,
                        "needYield" : 0,
                        "saveState" : 10,
                        "restoreState" : 10,
                        "isEOF" : 1,
                        "direction" : "forward",
                        "docsExamined" : 10000
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.6",
                "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
        },
        "ok" : 1
}

queryPlanner 部分

  • plannerVersion: 表示查詢最佳化器的版本。
  • namespace: 查詢涉及的集合名,即 test3.q1
  • indexFilterSet: 若為 true,表示查詢使用了索引過濾器;此處為 false,說明沒有使用。
  • parsedQuery: 顯示解析後的查詢條件,即查詢 age 欄位等於 200 的文件。
  • winningPlan: 描述被選擇的執行計劃。在這個案例中,執行計劃的 stage"COLLSCAN",意味著進行了全集合掃描(Collection Scan)。這意味著為了找到匹配的文件,MongoDB 需要遍歷整個 q1 集合,對每個文件應用 filter 中指定的條件(age: { $eq: 200 })。
  • rejectedPlans: 空陣列,表示沒有其他備選執行計劃被否決。如果有多個可行計劃,MongoDB 會選擇成本最低的一個作為 winningPlan,其餘的則記錄在此處。

executionStats 部分

這部分提供了實際執行查詢時的統計資訊:

  • executionSuccess: 指示查詢是否成功完成,true 表示成功。
  • nReturned: 返回的文件數量,這裡是 1,說明找到了一個年齡為 200 的文件。
  • executionTimeMillis: 執行查詢所花費的時間(毫秒),本例中為 2 毫秒。
  • totalKeysExamined: 檢視的索引鍵數量。由於未使用索引,此處為 0
  • totalDocsExamined: 檢視的文件數量,即全集合掃描過程中檢查過的文件總數,這裡為 10000,表明集合中有 10000 個文件被逐一檢查以找出符合 age: 200 的文件。
  • executionStages: 提供了更多關於執行階段的細節,與 winningPlan 相對應。這裡再次確認了進行了全集合掃描(COLLSCAN),並且實際檢視了 10000 個文件 (docsExamined) 才找到 1 個匹配的文件 (nReturned).

serverInfo 部分

  • 提供了執行 MongoDB 伺服器的主機名、埠、版本號以及 Git 版本資訊。

ok

  • 值為 1,表示命令執行成功。

2.3、新增limit查詢文件

db.q1.find({age:10}).limit(20)

db.q1.find({age:10}).limit(20).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test3.q1",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 10
                        }
                },
                "winningPlan" : {
                        "stage" : "LIMIT",
                        "limitAmount" : 20,
                        "inputStage" : {
                                "stage" : "COLLSCAN",
                                "filter" : {
                                        "age" : {
                                                "$eq" : 10
                                        }
                                },
                                "direction" : "forward"
                        }
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 4,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 10000,
                "executionStages" : {
                        "stage" : "LIMIT",
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 1,
                        "works" : 10002,
                        "advanced" : 1,
                        "needTime" : 10000,
                        "needYield" : 0,
                        "saveState" : 10,
                        "restoreState" : 10,
                        "isEOF" : 1,
                        "limitAmount" : 20,
                        "inputStage" : {
                                "stage" : "COLLSCAN",
                                "filter" : {
                                        "age" : {
                                                "$eq" : 10
                                        }
                                },
                                "nReturned" : 1,
                                "executionTimeMillisEstimate" : 1,
                                "works" : 10002,
                                "advanced" : 1,
                                "needTime" : 10000,
                                "needYield" : 0,
                                "saveState" : 10,
                                "restoreState" : 10,
                                "isEOF" : 1,
                                "direction" : "forward",
                                "docsExamined" : 10000
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.6",
                "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
        },
        "ok" : 1
}

可以明顯感受到加了limit後查詢速度變快了很多

但是如果我們查詢age9999的文件那麼還是得全表掃描一遍

此時我們就可以給該欄位加上索引

2.4、建立索引

db.collection.createIndex(keys, options)

引數:

  • keys:

    • 包含欄位和值對的文件,其中欄位是索引鍵,描述該欄位的索引型別
    • 對於欄位的上升索引,請指定為1,對於降序指定為-1
  • options:

    • 可選,包含一組控制索引建立的選項的文件
    選項 型別 描述
    background 布林 是否在後臺執行建立索引的過程,不阻塞對集合的操作false【預設】
    unique 布林 是否建立具有唯一性的索引 false【預設】
    name 字串 自定義索引名稱,如果不指定,mongodb將透過 下劃線 連線 索引欄位的名稱和排序規則 生成一個索引名稱。一旦建立不能修改,只能刪除再重新建立
    partialFilterExpression Document 僅為集合中符合條件的文件建立索引,降低建立和維護成本
    sparse 布林 僅為集合中具有指定欄位的文件建立索引 false 【預設】
    expireAfterSeconds integer單位 秒 用於 TTL 索引中 控制 文件儲存在集合中的時間
    storageEngine Document 指定儲存引擎配置
db.q1.ensureIndex({age:1})

檢視查詢計劃

db.q1.find({age:200}).explain("executionStats")
> db.q1.find({age:200}).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test3.q1",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 200
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "age" : 1
                                },
                                "indexName" : "age_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "age" : [
                                                "[200.0, 200.0]"
                                        ]
                                }
                        }
                },
                "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,
                        "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,
                                "keyPattern" : {
                                        "age" : 1
                                },
                                "indexName" : "age_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "age" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "age" : [
                                                "[200.0, 200.0]"
                                        ]
                                },
                                "keysExamined" : 1,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0
                        }
                }
        },
        "serverInfo" : {
                "host" : "localhost.localdomain",
                "port" : 27017,
                "version" : "4.4.6",
                "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
        },
        "ok" : 1
}
  • executionTimeMillis:執行耗時 1 毫秒。

  • totalKeysExaminedtotalDocsExamined:分別檢查了 1 個索引鍵和 1 個文件。由於使用了覆蓋索引(即索引包含了查詢所需的所有欄位),這裡的兩個值相等,意味著無需額外查詢文件。

檢視索引

> db.q1.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        {
                "v" : 2,
                "key" : {
                        "age" : 1
                },
                "name" : "age_1"
        }
]

image-20240426093010417

2.5、自定義索引名字

db.q1.ensureIndex({name:1},{name:"MyNameIndex"})

image-20240426102603193

3、檢視索引的大小

預設單位是位元組

db.q1.totalIndexSize()

image-20240426102044812

4、刪除索引

4.1、按名稱刪除索引

db.q1.dropIndex("MyNameIndex")

image-20240426102841487

4.2、刪除所有的索引

db.q1.dropIndexes()

image-20240426103015481

5、優缺點

5.1、優點:

  • 提高查詢效能:索引能夠大大加快資料查詢速度,特別是對於含有複雜查詢條件、排序、分組或聚合操作的查詢。
  • 支援高效排序:當查詢需要對特定欄位進行排序時,如果該欄位有索引,MongoDB可以直接利用索引來完成排序,避免了大量資料的內部排序操作,顯著提升效能。
  • 覆蓋查詢:如果一個索引包含了查詢所需的全部欄位,稱為“覆蓋索引”。在這種情況下,MongoDB可以直接從索引中獲取所有資料,而無需訪問實際文件,從而減少磁碟I/O操作,提高查詢效率。
  • 唯一性約束:建立唯一索引可以確保指定欄位的值在整個集合中唯一,防止插入重複資料,確保資料完整性。

5.2、缺點:

  • 佔用儲存空間:索引需要額外的儲存空間來儲存索引資料結構。隨著資料量的增長和索引數量的增加,儲存開銷會逐漸增大。需要根據實際業務需求權衡查詢效能與儲存成本。
  • 寫操作效能影響:插入、更新和刪除文件時,不僅要修改原資料,還要同步更新相關索引。對於寫密集型應用,大量的索引可能導致寫操作效能下降,尤其是當索引較多或索引欄位頻繁變動時。
  • 索引維護成本:隨著資料的變化,索引需要不斷維護和更新。對於大型資料集,索引重建可能需要消耗較長時間和系統資源。此外,隨著業務發展,可能需要定期評估和調整索引策略,以適應新的查詢模式。

相關文章