【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

原文地址:https://www.cnblogs.com/WilsonPan/p/12704474.html

时间: 2024-08-02 00:39:24

【Mongodb】视图 && 索引的相关文章

84. 从视图索引说Notes数据库(下)

作用和代价上文介绍了关系型数据库里的索引.Notes数据库里的索引隐藏在视图概念里(本文的讨论只针对Notes的视图索引,不包含全文索引.).开发人员创建的视图仅仅是存放在数据库里的一条设计文档,数据库引擎会依据它创建和更新索引.关系型数据库里的索引是从记录中抽取的数据排序而组成的数据结构(主要是B树),Notes视图的索引还包括未排序的列.计算值.分类.总计等等数据(数据结构仍然是B树,如果运气足够好的话,你会遇到Notes报出B-tree structure is invalid的错误).用

MongoDB数据库索引

前面的话 索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录.这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的.本文将详细介绍MongoDB数据库索引 引入 索引能够提高查询效率,如何体现呢?接下来使用性能分析函数explain()来进行分析说明 首先,插入10万条数据 接着,不创建索引,来寻找time范围在100和200之间的文档 由图中所知,tot

Mongodb的索引

1. 简单介绍 索引是为了加速查询. 假设没有索引,mongodb在查询时会做表扫描,假设集合非常大时,这个查询会非常慢. 一般对创建查询时的键都建立索引. 为排序字段建立索引,假设对未建立索引的字段sort,mongodb会将全部的数据取到内存中来排序, 假设集合大到不能在内存中排序,则mongodb会报错. 2. mongodb创建索引 创建索引使用ensureIndex命令. > db.people.ensureIndex({"username" : 1}); 上面语句对p

【MongoDB学习笔记20】MongoDB的索引

MongoDB的索引和关系型数据库的索引概念和功能是相同的: (1)不使用索引的搜索可以称为全表扫面,也就是说,服务器必须找完整个表才能查询整个结果: (2)建立索引后搜索,查询在索引中搜索,在索引的条目中找到条目以后,就可以直接跳转到目标文档的位置:这样的搜索比全表的搜索的速度要提高好几个数量级: 先向集合blog中添加1000000个文档: > for (i=0;i<1000000;i++){    ... db.users.insert(     ... {"i":i

MongoDB中索引的创建和使用详解

索引通常能够极大的提高查询的效率.在系统中使用查询时,应该考虑建立相关的索引.在MongoDB中创建索引相对比较容易. mongodb中的索引在概念上和大多数关系型数据库如MySQL是一样的.当你在某种情况下需要在MySQL中建立索引,这样的情景同样适合于MongoDB. 基本操作 索引是一种数据结构,他搜集一个集合中文档特定字段的值.MongoDB的查询优化器能够使用这种数据结构来快速的对集合(collection)中的文档(collection)进行寻找和排序.准确来说,这些索引是通过B-T

视图 索引

在视图上创建索引需要三个条件:一.视图必须绑定到架构.要做到这点,在 CREATE VIEW 语句中,必须加上 WITH SCHEMABINDING,如果是使用企业管理器,则在设计界面的空白处点击右键,属性,选中“绑定到架构”.二.索引必须是唯一索引.要做到这点,在 CREATE INDEX 中必须指定 UNIQUE.三.索引必须是聚集索引.要做到这点,在 CREATE INDEX 中必须指定 CLUSTERED.例:CREATE VIEW viewFoo WITH SCHEMABINDINGA

mongodb设置索引和id

ensureIndex() 方法 要创建一个索引,需要使用MongoDB 的ensureIndex()方法. 语法: ensureIndex() 方法的基本语法如下 yiibai.com >db.COLLECTION_NAME.ensureIndex({KEY:1}) 这里关键是要在其中创建索引,1是按升序排列的字段名称.要创建降序索引,需要使用-1. 例子 >db.mycol.ensureIndex({"title":1}) > 在ensureIndex()方法,可

创建视图索引

创建视图索引需要注意哪些事项 1.创建索引时提示该视图未绑定到架构(创建视图时加上schemabinding关键字则不能*号存在索引中) 解决方法:在创建视图的时候加上schemabinding 例句:CREATE VIEW [dbo].[viewTable] with schemabinding AS select ID from ..... 2.加上schemabinding建立索引的时候又提示必须先创建唯一聚集索引 解决方法: 在创建视图时加上UNIQUE  CLUSTERED 例句: C

MongoDB入门学习(四):MongoDB的索引

上一篇讲到了MongoDB的基本操作增删查改,对于查询来说,必须按照我们的查询要求去集合中,并将查找到的结果返回,在这个过程中其实是对整个集合中每个文档进行了扫描,如果满足我们的要求就添加到结果集中最后返回.对于小集合来说,这个过程没什么,但是集合中数据很大的时候,进行表扫描是一个非常恐怖的事情,于是有了索引一说,索引是用来加速查询的,相当于书籍的目录,有了目录可以很精准的定位要查找内容的位置,从而减少无谓的查找. 1.索引的类型 创建索引可以是在单个字段上,也可以是在多个字段上,这个根据自己的

SQL Server 视图索引

在视图上创建索引的另一个好处是:查询优化器开始在查询中使用视图索引,而不是直接在 FROM 子句中命令视图.这样一来,可从索引视图检索数据而无需重新编码,由此带来的高效率也使现有查询获益.在视图上创建的第一个索引必须是唯一聚集索引.在创建唯一聚集索引后,可创建其它非聚集索引.视图上的索引命名规则与表上的索引命名规则相同.唯一区别是表名由视图名替换.(Sql Server联机帮助)没研究过,说不出什么东西来,现在只把方法记下来.语句:Create VIEW vXXX WITH SCHEMABIND