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")
}
相关推荐
暴躁小师兄数据学院41 分钟前
【AI大数据工程师特训笔记】第05讲:关联查询
数据库·sql·oracle
倔强的石头_1 小时前
《Kingbase护城河》——跨平台环境下的数据库联调实战
数据库
lzhdim1 小时前
SQL 入门 17:MySQL 数据类型:从字符串到 JSON 的全面解析
数据库·sql·mysql·json
杨云龙UP1 小时前
Oracle RAC / ODA 生产环境指定 PDB 启动 SOP
linux·运维·数据库·oracle
kingwebo'sZone2 小时前
在Cent上安装Mysql 8.0的遇到的问题和解决办法
数据库·mysql·adb
幽络源小助理2 小时前
最新知识付费系统网站源码 PC+H5双端 附安装教程 – 幽络源源码网
大数据·数据库
小白考证进阶中2 小时前
Oracle OCP证书报考&考试全指南
数据库·oracle·oracle ocp·ocp认证·oracle认证·甲骨文认证·oracle ocp题库
Leon-Ning Liu3 小时前
【真实经验分享】 ORA-600 [qesmaGetTblSeg1]
数据库·oracle
与数据交流的路上3 小时前
MySQL 优化 -- 相关
数据库·mysql
Rooting++3 小时前
为什么mysql的表字段的collation会自动变
数据库·mysql