MongoDB中的物化视图

视图,为查询提供了便利。定义视图时, 可以包含复杂的集合查询逻辑或隐藏敏感信息。构建查询语句时,无需重复构建和维护聚合管道查询中的多个过程。Mongodb查询优化器也可以调整查询管道中的顺序,与视图查询中定义的查询条件一起进行优化。

视图实时返回聚合查询结果,能够获取到最新的数据。但用户或前端应用需要等待数据库实时计算结果。视图返回结果中的部分定义可以预先计算完成,不需要每次进行计算。物化视图可以满足这样的需求。

定义

物化视图,预先将聚合管道查询结果保存到硬盘中,并从硬盘直接读取结果。物化视图是merge和out过程的结果典型应用。

两种视图对比

物化视图与普通视图对比,有下面的差异和相同点。

  • 物化视图与普通视图,都返回聚合查询的结果。
  • 普通视图,实时查询数据库并返回结果,不会将数据保存到硬盘
  • 物化视图从硬盘直接读取数据。在聚合查询中,使用merge和out命令,将查询结果写入视图。物化视图可能不会实时获得数据,需要考虑定期更新或手动更新。
  • 标准视图不可添加删除索引。查询时查询优化器依赖于视图构建时的集合。物化视图可以添加索引,索引数据保存在硬盘上。
  • 性能上,物化视图直接从硬盘读取数据,效率高于普通视图。随着聚合管道查询复杂性的增加,这种优势会更加明显。

应用

某烘焙店在2019年一月底,产生了下面的数据

复制代码
db.bakesales.insertMany( [
   { date: new ISODate("2018-12-01"), item: "Cake - Chocolate", quantity: 2, amount: new NumberDecimal("60") },
   { date: new ISODate("2018-12-02"), item: "Cake - Peanut Butter", quantity: 5, amount: new NumberDecimal("90") },
   { date: new ISODate("2018-12-02"), item: "Cake - Red Velvet", quantity: 10, amount: new NumberDecimal("200") },
   { date: new ISODate("2018-12-04"), item: "Cookies - Chocolate Chip", quantity: 20, amount: new NumberDecimal("80") },
   { date: new ISODate("2018-12-04"), item: "Cake - Peanut Butter", quantity: 1, amount: new NumberDecimal("16") },
   { date: new ISODate("2018-12-05"), item: "Pie - Key Lime", quantity: 3, amount: new NumberDecimal("60") },
   { date: new ISODate("2019-01-25"), item: "Cake - Chocolate", quantity: 2, amount: new NumberDecimal("60") },
   { date: new ISODate("2019-01-25"), item: "Cake - Peanut Butter", quantity: 1, amount: new NumberDecimal("16") },
   { date: new ISODate("2019-01-26"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
   { date: new ISODate("2019-01-26"), item: "Cookies - Chocolate Chip", quantity: 12, amount: new NumberDecimal("48") },
   { date: new ISODate("2019-01-26"), item: "Cake - Carrot", quantity: 2, amount: new NumberDecimal("36") },
   { date: new ISODate("2019-01-26"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
   { date: new ISODate("2019-01-27"), item: "Pie - Chocolate Cream", quantity: 1, amount: new NumberDecimal("20") },
   { date: new ISODate("2019-01-27"), item: "Cake - Peanut Butter", quantity: 5, amount: new NumberDecimal("80") },
   { date: new ISODate("2019-01-27"), item: "Tarts - Apple", quantity: 3, amount: new NumberDecimal("12") },
   { date: new ISODate("2019-01-27"), item: "Cookies - Chocolate Chip", quantity: 12, amount: new NumberDecimal("48") },
   { date: new ISODate("2019-01-27"), item: "Cake - Carrot", quantity: 5, amount: new NumberDecimal("36") },
   { date: new ISODate("2019-01-27"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
   { date: new ISODate("2019-01-28"), item: "Cookies - Chocolate Chip", quantity: 20, amount: new NumberDecimal("80") },
   { date: new ISODate("2019-01-28"), item: "Pie - Key Lime", quantity: 3, amount: new NumberDecimal("60") },
   { date: new ISODate("2019-01-28"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
] );

现在计划统计每个月这家烘焙店的销售业绩, 包括每个自然月的销售数量和销售额。

构建物化视图

定义方法updateMonthlySales, 要求产生将每个月的销售统计信息放入视图。接受参数开始时间,用户指定开始时间,统计用户指定开始时间前的售卖信息。

复制代码
var updateMonthlySales = function(startDate) {
    db.bakesales.aggregate( [
        { $match: { date: {$gte: startDate}}},
        { $group: { _id: { $dateToString: { format: "%Y-%m", date: "$date"}}, sales_quantity: { $sum: "$quantity"}, sales_amount: { $sum: "$amount"}}},
        { $merge: { into: { coll: "monthlybakesales" }, on: "_id",  whenMatched: "replace", whenNotMatched: "insert" }}
        ])
}

$match方法查询出指定时间后的销售数据

$group方法,按照自然月统计销售数量和销售金额信息

$merge方法,将查询结果放到视图monthlybacksales中。当月销售数据存在时,替换掉视图中当月的数据。当月数据不存在时,将统计后当月销售数据插入视图。

运行方法updateMonthlySales, 产生初始统计数据

vb 复制代码
`updateMonthlySales(new ISODate("1970-01-01"))`

查询物化视图

运行updateMonthlySales方法后,数据已经保存到视图monthlybacksales中。

复制代码
db.monthlybakesales.find().sort("_id")
/* 1 */
{
	"_id" : "2018-12",
	"sales_quantity" : 41,
	"sales_amount" : Decimal128("506")
},

/* 2 */
{
	"_id" : "2019-01",
	"sales_quantity" : 102,
	"sales_amount" : Decimal128("1142")
},

更新物化视图

假设在2019年2月份,该烘焙店产生了下面的新销售数据

复制代码
db.bakesales.insertMany( [
   { date: new ISODate("2019-01-28"), item: "Cake - Chocolate", quantity: 3, amount: new NumberDecimal("90") },
   { date: new ISODate("2019-01-28"), item: "Cake - Peanut Butter", quantity: 2, amount: new NumberDecimal("32") },
   { date: new ISODate("2019-01-30"), item: "Cake - Red Velvet", quantity: 1, amount: new NumberDecimal("20") },
   { date: new ISODate("2019-01-30"), item: "Cookies - Chocolate Chip", quantity: 6, amount: new NumberDecimal("24") },
   { date: new ISODate("2019-01-31"), item: "Pie - Key Lime", quantity: 2, amount: new NumberDecimal("40") },
   { date: new ISODate("2019-01-31"), item: "Pie - Banana Cream", quantity: 2, amount: new NumberDecimal("40") },
   { date: new ISODate("2019-02-01"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") },
   { date: new ISODate("2019-02-01"), item: "Tarts - Apple", quantity: 2, amount: new NumberDecimal("8") },
   { date: new ISODate("2019-02-02"), item: "Cake - Chocolate", quantity: 2, amount: new NumberDecimal("60") },
   { date: new ISODate("2019-02-02"), item: "Cake - Peanut Butter", quantity: 1, amount: new NumberDecimal("16") },
   { date: new ISODate("2019-02-03"), item: "Cake - Red Velvet", quantity: 5, amount: new NumberDecimal("100") }
] )

为了更新物化视图中的数据,运行方法updateMonthlySales方法

复制代码
updateMonthlySales(new ISODate("2019-01-01"))

查询更新后的结果

复制代码
db.monthlybakesales.find().sort("_id")
/* 1 */
{
	"_id" : "2018-12",
	"sales_quantity" : 41,
	"sales_amount" : Decimal128("506")
},

/* 2 */
{
	"_id" : "2019-01",
	"sales_quantity" : 102,
	"sales_amount" : Decimal128("1142")
},

/* 3 */
{
	"_id" : "2019-02",
	"sales_quantity" : 15,
	"sales_amount" : Decimal128("284")
}
相关推荐
bbsh209914 分钟前
WebFuture:ASP.NET启动失败报500.30错误
数据库·webfuture
胆大的31 分钟前
SQL 盲注(Blind SQL Injection)
数据库·sql·安全性测试
数据库幼崽1 小时前
MySQL 排查全局锁
数据库·mysql
啃火龙果的兔子2 小时前
华为云二级、多级域名配置
数据库·华为云
isNotNullX2 小时前
kettle好用吗?相较于国产ETL工具有哪些优劣之处?
大数据·数据库·数据仓库·信息可视化·etl
姜豆豆耶3 小时前
Oracle client 静默安装
数据库·oracle·dba
秋意零4 小时前
【排坑指南】MySQL初始化后,Nacos与微服务无法连接??
运维·数据库·mysql·微服务·nacos·报错
麓殇⊙4 小时前
操作系统期末复习--操作系统初识以及进程与线程
java·大数据·数据库
fouryears_234174 小时前
深入理解 MySQL 事务:保障数据操作的原子性与一致性
数据库·mysql
凌冰_5 小时前
Springboot MyBatis 数据库连接池
数据库·spring boot·mybatis