【Mongodb】視圖 && 索引

来源:https://www.cnblogs.com/WilsonPan/archive/2020/04/15/12704474.html
-Advertisement-
Play Games

Mongodb視圖可以讓查詢數據變的更加方便,索引讓查詢數據變得更加快捷,本文介紹如何使用Mongodb的視圖功能和索引功能 ...


 

準備工作

準備2個集合的數據,後面視圖和索引都會用到
1個訂單集合,一個收款信息集合

var orders = new Array();
var shipping = new Array();
var addresses = ["廣西省玉林市", "湖南省岳陽市", "湖北省荊州市", "甘肅省蘭州市", "吉林省松原市", "江西省景德鎮", "遼寧省沈陽市", "福建省廈門市", "廣東省廣州市", "北京市朝陽區"];

for (var i = 10000; i < 20000; i++) {
    var orderNo = i + Math.random().toString().substr(2, 5);
    orders[i] = { orderNo: orderNo, userId: i, price: Math.round(Math.random() * 10000) / 100, qty: Math.floor(Math.random() * 10) + 1, orderTime: new Date(new Date().setSeconds(Math.floor(Math.random() * 10000))) };

    var address = addresses[Math.floor(Math.random() * 10)];
    shipping[i] = { orderNo: orderNo, address: address, recipienter: "Wilson", province: address.substr(0, 3), city: address.substr(3, 3) }
}
db.order.insert(orders);
db.shipping.insert(shipping);

 

視圖

概述

A MongoDB view is a queryable object whose contents are defined by an aggregation pipeline on other collections or views. MongoDB does not persist the view contents to disk. A view’s content is computed on-demand when a client queries the view. MongoDB can require clients to have permission to query the view. MongoDB does not support write operations against views.

Mongodb的視圖基本上和SQL的視圖一樣

  • 數據源(集合或視圖)
  • 提供查詢
  • 不實際存儲硬碟
  • 客戶端發起請求查詢時計算而得

1. 創建視圖

有兩種方法創建視圖

db.createCollection(
  "<viewName>",
  {
    "viewOn" : "<source>",
    "pipeline" : [<pipeline>],
    "collation" : { <collation> }
  }
)
db.createView(
  "<viewName>",
  "<source>",
  [<pipeline>],
  {
    "collation" : { <collation> }
  }
)

一般使用db.createView

viewName : 必須,視圖名稱

source : 必須,數據源,集合/視圖

[<pipeline>] : 可選,一組管道,可見管道是Mongodb比較重要的一環

 

1.1 單個集合創建視圖

假設現在查看當天最高的10筆訂單視圖,例如後臺某個地方需要實時顯示金額最高的訂單

db.createView(
    "orderInfo",         //視圖名稱
    "order",             //數據源   
    [
        //篩選符合條件的訂單,大於當天,這裡要註意時區
        { $match: { "orderTime": { $gte: ISODate("2020-04-13T16:00:00.000Z") } } },
        //按金額倒序
        { $sort: { "price": -1 } },
        //限制10個文檔
        { $limit: 10 },
        //選擇要顯示的欄位
        //0: 排除欄位,若欄位上使用(_id除外),就不能有其他包含欄位
        //1: 包含欄位
        { $project: { _id: 0, orderNo: 1, price: 1, orderTime: 1 } }
    ]
)

然後就可以直接使用orderInfo這個視圖查詢數據

db.orderInfo.find({})

返回結果

{ "orderNo" : "1755149436", "price" : 100, "orderTime" : ISODate("2020-04-14T13:49:42.220Z") }
{ "orderNo" : "1951423853", "price" : 99.99, "orderTime" : ISODate("2020-04-14T15:08:07.240Z") }
{ "orderNo" : "1196303215", "price" : 99.99, "orderTime" : ISODate("2020-04-14T15:15:41.158Z") }
{ "orderNo" : "1580069456", "price" : 99.98, "orderTime" : ISODate("2020-04-14T13:41:07.199Z") }
{ "orderNo" : "1114480559", "price" : 99.98, "orderTime" : ISODate("2020-04-14T13:31:58.150Z") }
{ "orderNo" : "1229542817", "price" : 99.98, "orderTime" : ISODate("2020-04-14T15:15:35.162Z") }
{ "orderNo" : "1208031402", "price" : 99.94, "orderTime" : ISODate("2020-04-14T14:13:02.160Z") }
{ "orderNo" : "1680622670", "price" : 99.93, "orderTime" : ISODate("2020-04-14T15:17:25.210Z") }
{ "orderNo" : "1549824953", "price" : 99.92, "orderTime" : ISODate("2020-04-14T13:09:41.196Z") }
{ "orderNo" : "1449930147", "price" : 99.92, "orderTime" : ISODate("2020-04-14T15:16:15.187Z") }
 

1.2 多個集合創建視圖

其實跟單個是集合是一樣,只是多了$lookup連接操作符,視圖根據管道最終結果顯示,所以可以關聯多個集合(若出現這種情況就要考慮集合設計是否合理,mongodb本來就是文檔型資料庫)

db.orderDetail.drop()
db.createView(
    "orderDetail",
    "order",
    [
        { $lookup: { from: "shipping", localField: "orderNo", foreignField: "orderNo", as: "shipping" } },
        { $project: { "orderNo": 1, "price": 1, "shipping.address": 1 } }
    ]
)

查詢視圖,得到如下結果

{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6c3"), "orderNo" : "1000039782", "price" : 85.94, "shipping" : [ { "address" : "北京市朝陽區" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6c4"), "orderNo" : "1000102128", "price" : 29.04, "shipping" : [ { "address" : "吉林省松原市" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6c5"), "orderNo" : "1000214514", "price" : 90.69, "shipping" : [ { "address" : "湖南省岳陽市" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6c6"), "orderNo" : "1000337987", "price" : 75.05, "shipping" : [ { "address" : "遼寧省沈陽市" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6c7"), "orderNo" : "1000468969", "price" : 76.84, "shipping" : [ { "address" : "江西省景德鎮" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6c8"), "orderNo" : "1000572219", "price" : 60.25, "shipping" : [ { "address" : "江西省景德鎮" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6c9"), "orderNo" : "1000611743", "price" : 19.14, "shipping" : [ { "address" : "廣東省廣州市" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6ca"), "orderNo" : "1000773917", "price" : 31.5, "shipping" : [ { "address" : "北京市朝陽區" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6cb"), "orderNo" : "1000879146", "price" : 76.16, "shipping" : [ { "address" : "吉林省松原市" } ] }
{ "_id" : ObjectId("5e95af8c4ef6faf974b4a6cc"), "orderNo" : "1000945977", "price" : 93.98, "shipping" : [ { "address" : "遼寧省沈陽市" } ] }

可以看到,mongodb不是像SQL那樣把連接的表當成列列出,而是把連接結果放在數組裡面,這很符合Mongodb文檔型結構。

 

2. 修改視圖

假設現在需要增加一個數量的欄位

db.runCommand({
    collMod: "orderInfo",
    viewOn: "order",
    pipeline: [
        { $match: { "orderTime": { $gte: ISODate("2020-04-13T16:00:00.000Z") } } },
        { $sort: { "price": -1 } },
        { $limit: 10 },
        //增加qty
        { $project: { _id: 0, orderNo: 1, price: 1, qty: 1, orderTime: 1 } }
    ]
})

當然,也可以刪除視圖,重新用db.createView()創建視圖

 

3. 刪除視圖

db.orderInfo.drop();

 

索引

概述

Indexes support the efficient execution of queries in MongoDB. Without indexes, MongoDB must perform a collection scan, i.e. scan every document in a collection, to select those documents that match the query statement. If an appropriate index exists for a query, MongoDB can use the index to limit the number of documents it must inspect.

索引能提供高效的查詢,沒有索引的查詢,mongole執行集合掃描,相當於SQL SERVER的全表掃描,掃描每一個文檔。

數據存在存儲介質上,大多數情況是為了查詢,查詢的快慢直接影響用戶體驗,mongodb索引也是空間換時間,添加索引,CUD操作都會導致索引重新生成,影響速度。

 

1. 準備工作

1.1 準備200W條數據

var orderNo = 100 * 10000;
for (var i = 0; i < 100; i++) {
    //分批次插入,每次20000條
    var orders = new Array();
    for (var j = 0; j < 20000; j++) {
        var orderNo = orderNo++;
        orders[j] = { orderNo: orderNo, userId: i + j, price: Math.round(Math.random() * 10000) / 100, qty: Math.floor(Math.random() * 10) + 1, orderTime: new Date(new Date().setSeconds(Math.floor(Math.random() * 10000))) };
    }
    //不需寫入確認
    db.order.insert(orders, { writeConcern: { w: 0 } });
}

 

1.2 mongodb的查詢計劃

db.collection.explain().<method(...)>

 

一般使用執行統計模式,例如

db.order.explain("executionStats").find({orderNo:1000000})

返回的executionStats對象欄位說明

部分欄位說明

欄位說明
executionSuccess 是否執行成功
nReturned 返回匹配文檔數量
executionTimeMillis 執行時間,單位:毫秒
totalKeysExamined 索引檢索數目
totalDocsExamined 文檔檢索數目

查看未加索引前查詢計劃

db.order.explain("executionStats").find({orderNo:1000000})

截取部分返回結果,可以看出

  • executionTimeMillis : 用時1437毫秒
  • totalDocsExamined : 掃描文檔200W
  • executionStages.stage : 集合掃描
"executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 1,
    "executionTimeMillis" : 1437,
    "totalKeysExamined" : 0,
    "totalDocsExamined" : 2000000,
    "executionStages" : {
            "stage" : "COLLSCAN",

 

1.3 查看當前集合統計信息

db.order.stats()

截取部分信息,可以看出現在存儲文件大小大概為72M

{
        "ns" : "mongo.order",
        "size" : 204000000,
        "count" : 2000000,
        "avgObjSize" : 102,
        "storageSize" : 74473472,

 

2. 創建索引

db.order.createIndex({ orderNo: 1 }, { name: "ix_orderNo" })

索引名稱不是必須,若不指定,按 欄位名稱_排序類型組合自動生成,索引名稱一旦創建不能修改,若要修改,只能刪除索引重新生成索引,建議還是建索引的時候就把索引名稱設置好。

 

2.1 執行查詢計劃

db.order.explain("executionStats").find({orderNo:1000000})

截取部分結果,直觀就可以感覺查詢速度有了質的提升,再看查詢計劃更加驚訝

  • nReturned : 匹配到1個文檔
  • executionTimeMillis : 0,呃。。
  • totalKeysExamined : 總共檢索了1個索引
  • totalDocsExamined : 總共檢索了1個文檔
  • executionStages.stage : FETCH,根據索引去檢索指定文檔,像SQL的Index Seek
 "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 0,
                "totalKeysExamined" : 1,
                "totalDocsExamined" : 1,
                "executionStages" : {
                        "stage" : "FETCH"

 

這裡只介紹最簡單的單個欄位索引,mongodb還有很多索引

  • 複合索引(Compound Indexes):對多個欄位做索引
  • 多鍵索引(Multikey Indexes): 一個欄位多個值做索引,通常是數組
  • 全文索引(Text Indexes): 對文本檢索,可以對欄位設置不同權重
  • 通配符索引(Wildcard Indexes):可以將對象的所有/指定的值做索引
  • 更多

 

參考文章


Views — MongoDB Manual

Indexes — MongoDB Manual

轉發請標明出處:https://www.cnblogs.com/WilsonPan/p/12704474.html

 

 


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

-Advertisement-
Play Games
更多相關文章
  • ![](https://img2020.cnblogs.com/blog/1056386/202004/1056386-20200415231509745-316250986.png) ![](https://img2020.cnblogs.com/blog/1056386/202004/10563... ...
  • Mongodb從4.0開始支持副本集的多文檔事務,4.2支持分片集群的多文檔事務,本文介紹Mongodb如何快速搭建副本集,使用事務。 ...
  • package com.nll.test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java. ...
  • 使用limit分頁查詢時,做delete操作,會導致丟失數據 [TOC] 一、準備數據 1.1 mysql數據腳本 mysql SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; Table structure for test_so_item DROP T ...
  • 1. 備份 2. 恢復 3. 傳輸到另一個伺服器恢複數據庫 "scp" r /home/test.tar root@host:/home/others/ 4. Linux "passwd" 命令用來更改使用者的密碼. 忘記密碼可以使用 ...
  • hello,小伙伴們大家好,今天給大家分享的開源項目是 ,這個工具方便我們更直觀的操作數據。對於剛剛學習mongo的小伙伴來說可以更快的掌握,入門。數據可以直接導出csv,json,mysql等格式,也可以生成對應的代碼比如:Python, Java, Node.js, C 代碼等等。這些是大家日常 ...
  • 如何讓mysql按照兩個或多個欄位排序 錯誤方式: 這種方式兩個欄位都是降序的(and隔開哪個,第二個參數不起作用。) 正確方式: ...
  • SQL2008 的收縮日誌 由於SQL2008對文件和日誌管理進行了優化,所以以下語句在SQL2005中可以運行但在SQL2008中已經被取消:SQL2005 清空日誌的方法:Backup Log DNName with no_loggodump transaction DNName with no ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...