当前位置: 首页 > news >正文

网站开发需求分析说明重庆娱乐公司

网站开发需求分析说明,重庆娱乐公司,网站服务器做缓存,公司标志logo设计免费“我在 SQL 和规范化数据库方面拥有丰富的经验#xff0c;但我只是 MongoDB 的初学者。如何建立一对 N 关系模型#xff1f;” 这是我从参加 MongoDB 分享日活动的用户那里得到的最常见问题之一。 我对这个问题没有简短的答案#xff0c;因为方法不只有一种#xff0c;还有… “我在 SQL 和规范化数据库方面拥有丰富的经验但我只是 MongoDB 的初学者。如何建立一对 N 关系模型” 这是我从参加 MongoDB 分享日活动的用户那里得到的最常见问题之一。 我对这个问题没有简短的答案因为方法不只有一种还有很多种方法。MongoDB 拥有丰富而细致的词汇来表达 SQL 中的内容这些词汇被扁平化为术语“One-to-N”。让我带您了解一下您在建模一对 N 关系时的选择。 这里有很多值得讨论的内容在这篇文章中我将讨论建模一对 N 关系的三种基本方法。我还将介绍更复杂的模式设计包括非规范化和双向引用。我将回顾所有的选择并为您提供一些建议以便您在建模单个一对 N 关系时可能会考虑的数千个选择中进行选择。想了解什么是**「数据库非规范化」**以及何时不对数据进行非规范化您可以直接跳转到文章末尾。 许多初学者认为在 MongoDB 中进行“一对多”建模的唯一方法是将子文档数组嵌入到父文档中但事实并非如此。仅仅因为您可以嵌入文档并不意味着您应该嵌入文档。 在设计 MongoDB 模式时您需要从一个在使用 SQL 和规范化表时永远不会考虑的问题开始**关系的基数是什么**不那么正式地说**您需要更细致地描述您的“一对多”关系是“一对几个”、“一对多”还是“一对数”**根据具体情况您可以使用不同的格式来建模关系。 基础知识一对多建模 “一对多”的一个例子可能是一个人的地址。这是嵌入的一个很好的用例。 您可以将地址放入 Person 对象内部的数组中 db.person.findOne() {name: Kate Monster,ssn: 123-456-7890,addresses : [{ street: 123 Sesame St, city: Anytown, cc: USA },{ street: 123 Avenue Q, city: New York, cc: USA }] } 这种设计具有嵌入的所有优点和缺点。主要的优点是你不必执行单独的查询来获取嵌入的细节主要的缺点是你无法以独立的实体方式访问嵌入的细节。 例如如果你正在建模一个任务跟踪系统每个人都会被分配一些任务。将任务嵌入到人员文档中会使像“显示明天到期的所有任务”这样的查询变得比必要的复杂。我将在本文的后面部分介绍一种更适合检索这种用例数据的设计。 基础知识一对多 “一对多”的一个例子可能是一个备件订购系统中的产品零件。 每个产品可能有多达数百个备件但绝不会超过几千个左右所有那些不同尺寸的螺栓、垫圈和垫片都会相加。这是引用的一个很好的使用案例。你可以将零件的ObjectID放在产品文档的数组中。 *对于这些示例我使用2字节的ObjectID因为它们更容易阅读。实际的代码将使用12字节的ObjectID。 每个零件都有自己的文档 db.parts.findOne() {_id : ObjectID(AAAA),partno : 123-aff-456,name : #4 grommet,qty: 94,cost: 0.94, price: 3.99每个产品都有自己的文档其中包含了构成该产品的零件的ObjectID引用数组 db.products.findOne() {name : left-handed smoke shifter,manufacturer : Acme Corp,catalog_number: 1234,parts : [ // array of references to Part documentsObjectID(AAAA), // reference to the #4 grommet aboveObjectID(F17C), // reference to a different PartObjectID(D2AA),// etc]然后你将使用应用程序级联接来检索特定产品的零件 // Fetch the Product document identified by this catalog numberproduct db.products.findOne({catalog_number: 1234});// Fetch all the Parts that are linked to this Productproduct_parts db.parts.find({_id: { $in : product.parts } } ).toArray() ;为了高效操作您需要在“products.catalog_number”上有一个索引。请注意“parts._id”上始终有一个索引因此查询始终高效。 这种引用方式与嵌入具有互补的优点和缺点。**每个部分都是一个独立的文档因此可以轻松地独立搜索和更新它们。**使用此模式的一个权衡是必须执行第二个查询才能获取有关产品零件的详细信息。但是在我们讨论非规范化之前请保持这个想法。 作为额外的好处此模式允许您拥有多个产品使用的单独部件因此您的一对 N 模式就变成了 N 对 N 模式而不需要连接表 基础知识一到百千万 “one-to-squillions”的一个例子可能是收集不同机器的日志消息的事件日志系统。 任何给定的主机都可以生成足够的消息来溢出 16 MB 文档大小即使您在数组中存储的只是 ObjectID。这是“父引用”的经典用例。您将有一个主机文档然后将主机的 ObjectID 存储在日志消息的文档中。 db.hosts.findOne() {_id : ObjectID(AAAB),name : goofy.example.com,ipaddr : 127.66.66.66 }db.logmsg.findOne() {time : ISODate(2014-03-28T09:42:41.382Z),message : cpu is on fire!,host: ObjectID(AAAB) // Reference to the Host document }您可以使用略有不同应用程序级联接来查找主机的最新 5,000 条消息 // find the parent ‘host’ documenthost db.hosts.findOne({ipaddr : 127.66.66.66}); // assumes unique index// find the most recent 5000 log message documents linked to that hostlast_5k_msg db.logmsg.find({host: host._id}).sort({time : -1}).limit(5000).toArray()回顾 因此即使在这个基本级别设计 MongoDB 模式时也比为规范化数据库设计类似的关系数据库模式时需要考虑更多。您需要考虑两个因素 ● 一对 N 的“N”端的实体是否需要独立 ● 关系的基数是多少是一对多吗一对多还是一比十呢 基于这些因素您可以选择三种基本的一对 N 模式设计之一 ● 如果基数是一对多并且不需要在父对象的上下文之外访问嵌入的对象则嵌入 N 端。 ● 如果基数是一对多或者 N 端对象由于任何原因应该独立则使用对 N 端对象的引用数组。 ● 如果基数为 1 到 squillions请使用对 N 端对象中的 One-side 的引用。 中级双向参考 如果您想变得更奇特一点您可以结合两种技术并在模式中包含两种引用样式既具有从“一”侧到“多”侧的引用又具有从“多”侧到“一”侧的引用。 举个例子让我们回到任务跟踪系统。有一个保存“人员”文档的“人员”集合一个保存任务文档的“任务”集合以及从人员到任务的一对 N 关系。应用程序需要跟踪人员拥有的所有任务因此我们需要将人员引用到任务。 通过对 Task 文档的引用数组单个 Person 文档可能如下所示 db.person.findOne() {_id: ObjectID(AAF1),name: Kate Monster,tasks [ // array of references to Task documentsObjectID(ADF9), ObjectID(AE02),ObjectID(AE73) // etc] }另一方面在某些其他上下文中此应用程序将显示任务列表例如多人项目中的所有任务并且需要快速找到负责每个任务的人员。为此您可以通过在任务文档中添加对人员的附加引用来优化数据检索。 db.tasks.findOne() {_id: ObjectID(ADF9), description: Write lesson plan,due_date: ISODate(2014-04-01),owner: ObjectID(AAF1) // Reference to Person document }此设计具有“一对多”模式的所有优点和缺点但还添加了一些内容。将额外的“所有者”引用放入任务文档中意味着可以快速轻松地找到任务的所有者但这也意味着如果您需要将任务重新分配给另一个人则需要执行两次更新而不仅仅是一次。具体来说您必须更新从人员到任务文档的引用以及从任务到人员的引用。 *对于正在阅读本文的关系数据库专家来说您是对的在规范化数据库模型上使用此模式设计意味着不再可能通过单个原子更新将任务重新分配给新人员。这对于我们的任务跟踪系统是可以的您需要考虑这是否适合您的特定用例。 中级具有一对多关系的数据库非规范化 除了对各种关系进行建模之外您还可以将非规范化添加到模式中。这可以消除在某些情况下执行应用程序级联接的需要但代价是执行更新时会增加一些复杂性。一个例子将有助于阐明这一点。 数据库非规范化从多到一 对于零件示例您可以将零件名称非规范化到“parts[]”数组中。作为参考这里是没有非规范化的产品文档版本。 db.products.findOne() {name : left-handed smoke shifter,manufacturer : Acme Corp,catalog_number: 1234,parts : [ // array of references to Part documentsObjectID(AAAA), // reference to the #4 grommet aboveObjectID(F17C), // reference to a different PartObjectID(D2AA),// etc] }非规范化意味着您在显示产品的所有部件名称时不必执行应用程序级联接但如果您需要有关部件的任何其他信息则必须执行该联接。 db.products.findOne() {name : left-handed smoke shifter,manufacturer : Acme Corp,catalog_number: 1234,parts : [{ id : ObjectID(AAAA), name : #4 grommet }, // Part name is denormalized{ id: ObjectID(F17C), name : fan blade assembly },{ id: ObjectID(D2AA), name : power switch },// etc] }虽然可以更轻松地获取部件名称但这只会在应用程序级连接中添加一些客户端工作 // Fetch the product documentproduct db.products.findOne({catalog_number: 1234}); // Create an array of ObjectID()s containing *just* the part numberspart_ids product.parts.map( function(doc) { return doc.id } );// Fetch all the Parts that are linked to this Productproduct_parts db.parts.find({_id: { $in : part_ids } } ).toArray() ;**非规范化可以为您节省非规范化数据的查找但代价是更新成本更高**因为您向数据库添加了一些数据冗余如果您已将部件名称非规范化到产品文档中那么当您更新部件名称时您还必须更新“产品”集合中出现的每个位置。 **仅当读取与更新比率较高时非规范化才有意义。**如果您经常读取非规范化数据但很少更新它那么为了获得更高效的查询性能付出较慢的写入性能和更复杂的冗余数据更新的代价通常是有意义的。随着更新相对于查询变得更加频繁非规范化带来的节省会减少。 例如假设零件名称很少变化但现有数量经常变化。这意味着虽然出于数据完整性的目的将部件名称非规范化到产品文档中是有意义的但对现有数量进行非规范化是没有意义的。 **另请注意如果对字段进行非规范化您将失去对该字段执行原子和独立更新的能力。**就像双向引用一样如果您先更新零件文档中的零件名称然后再更新产品文档中的零件名称则可能会出现数据异常因为将存在一个亚秒间隔其中产品文档中的非规范化名称不会反映零件文档中新的、更新的值。 数据库从一到多的非规范化 您还可以将字段从“一”侧非规范化为“多”侧 db.parts.findOne() {_id : ObjectID(AAAA),partno : 123-aff-456,name : #4 grommet,product_name : left-handed smoke shifter, // Denormalized from the ‘Product’ documentproduct_catalog_number: 1234, // Dittoqty: 94,cost: 0.94,price: 3.99 }但是如果您已将产品名称非规范化到零件文档中那么当您更新产品名称时您还必须更新它在“零件”集合中出现的每个位置以避免数据异常。这可能是一个更昂贵的更新因为您要更新多个部件而不是单个产品。因此以这种方式进行非规范化时考虑读写比率就显得尤为重要。 中级具有一对一关系的数据库反规范化 您还可以将一对一的关系非规范化。这可以通过以下两种方式之一进行您可以将有关“一”侧的信息来自“hosts”文档放入“squillions”侧日志条目或者可以将“squillions”中的摘要信息放入“一”侧。 下面是“squillions”方面的非规范化示例。我将把主机的 IP 地址从“一侧”添加到单独的日志消息中 db.logmsg.findOne() {time : ISODate(2014-03-28T09:42:41.382Z),message : cpu is on fire!,ipaddr : 127.66.66.66,host: ObjectID(AAAB) }您对来自特定 IP 地址的最新消息的查询变得更加容易现在只需一个查询而不是两个。 last_5k_msg db.logmsg.find({ipaddr : 127.66.66.66}).sort({time : -1}).limit(5000).toArray() 事实上如果您只想在“one”一侧存储有限数量的信息则可以将其全部非规范化到“squillions”一侧并完全摆脱“一”侧集合 db.logmsg.findOne() {time : ISODate(2014-03-28T09:42:41.382Z),message : cpu is on fire!,ipaddr : 127.66.66.66,hostname : goofy.example.com, }另一方面您也可以非规范化为“一”侧。假设您希望在“主机”文档中保留来自某个主机的最后 1,000 条消息。您可以使用 MongoDB 2.4 中引入的 $each / $slice 功能来保持该列表排序并且仅保留最后 1,000 条消息 日志消息保存在“logmsg”集合以及“hosts”文档中的非规范化列表中。这样当消息超出“hosts.logmsgs”数组时该消息就不会丢失。 // Get log message from monitoring system logmsg get_log_msg(); log_message_here logmsg.msg; log_ip logmsg.ipaddr;// Get current timestamp now new Date()// Find the _id for the host I’m updating host_doc db.hosts.findOne({ipaddr : log_ip },{_id:1}); // Don’t return the whole document host_id host_doc._id;// Insert the log message, the parent reference, and the denormalized data into the ‘many’ side db.logmsg.save({time : now, message : log_message_here, ipaddr : log_ip, host : host_id ) });// Push the denormalized log message onto the ‘one’ side db.hosts.update( {_id: host_id }, {$push : {logmsgs : { $each: [ { time : now, message : log_message_here } ],$sort: { time : 1 }, // Only keep the latest ones $slice: -1000 } // Only keep the latest 1000}} );请注意使用投影规范 ( {_id:1} ) 可以防止 MongoDB 通过网络传输整个“hosts”文档。通过告诉 MongoDB 仅返回 _id 字段您可以将网络开销减少到存储该字段所需的几个字节加上有线协议开销。 正如“一对多”情况下的非规范化一样您需要考虑读取与更新的比率。仅当日志消息相对于应用程序需要查看单个主机的所有消息的次数来说并不频繁时将日志消息非规范化到“主机”文档中才有意义。如果您希望查看数据的频率低于更新数据的频率那么这种特殊的非规范化是一个坏主意。 回顾 在本节中我介绍了您在嵌入、子引用或父引用基础知识之后所拥有的其他选择。 ● 如果双向引用可以优化您的架构并且您愿意付出没有原子更新的代价那么您可以使用双向引用。 ● 如果您正在引用则可以将数据从“一”侧反规范化 到“N”侧或者从“N”侧反规范化到“一”侧。 在决定数据库非规范化时请考虑以下因素 ● 您无法对非规范化数据执行原子更新。 ● 仅当读写比率较高时非规范化才有意义。 看看所有这些数据库非规范化选择 特别是数据库反规范化为您提供了很多选择如果关系中有 8 个反规范化候选者则有 2 8 (1,024) 种不同的反规范化方式包括根本不进行反规范化。将其乘以三种不同的引用方式您就有超过 3,000 种不同的方式来建模关系。 你猜怎么了你现在陷入了“选择悖论”。因为你有很多潜在的方法来建模“一对N”关系所以你选择如何建模它变得更加困难。 数据库非规范化经验法则您的彩虹指南 以下是一些“经验法则”可以指导您完成这些无数但不是无限的选择 1、赞成嵌入除非有令人信服的理由不这样做。 2、需要单独访问一个对象是不嵌入它的一个令人信服的理由。 3、数组不应该无限增长。如果“多”端有超过几百个文档则不要嵌入它们如果“多”端有超过几千个文档请不要使用 ObjectID 引用数组。高基数数组是不嵌入的一个令人信服的理由。 4、不要害怕应用程序级联接如果正确索引并使用投影说明符那么应用程序级联接几乎不会比关系数据库中的服务器端联接贵。 5、考虑非规范化的读写比。大部分被读取且很少更新的字段是非规范化的良好候选者。如果您对经常更新的字段进行非规范化那么查找和更新所有冗余数据实例的额外工作可能会淹没您从非规范化中获得的节省。 6、与 MongoDB 一样如何建模数据完全取决于特定应用程序的数据访问模式。您希望构建数据以匹配应用程序查询和更新数据的方式。 你的彩虹指南 在 MongoDB 中建模“一对多”关系时您有多种选择因此您必须仔细考虑数据的结构。您需要考虑的主要标准是 ● 关系的基数是什么是“一对多”、“一对多”还是“一对几” ● 您需要单独访问“N”侧的对象还是仅在父对象的上下文中访问 ● 特定字段的更新与读取之比是多少 您构建数据的主要选择是 ● 对于“一对多”您可以使用一系列嵌入文档。 ● 对于“一对多”或者“N”侧必须独立的情况您应该使用引用数组。如果可以优化您的数据访问模式您还可以在“N”侧使用“父引用”。 ● 对于“one-to-squillions”您应该在存储“N”侧的文档中使用“parent-reference”。 一旦您决定了数据库设计中数据的总体结构您就可以如果您选择跨多个文档对数据进行非规范化方法是将数据从“One”侧非规范化到“N”侧或者从“N”侧非规范化数据。将“N”侧插入“One”侧。您只需对经常读取、读取次数远多于更新次数以及不需要强一致性的字段执行此操作因为更新非规范化值更慢、更昂贵并且不是原子的。 生产力和灵活性 所有这一切的结果是 MongoDB 使您能够设计数据库模式以满足应用程序的需求。您可以在 MongoDB 中构建数据使其轻松适应变化并支持充分利用应用程序所需的查询和更新。 附录一什么是数据库非规范化 数据库非规范化技术背后有一个非常简单的原则一起访问的数据应该存储在一起。非规范化是复制字段或从现有字段派生新字段的过程。非规范化数据库可以在多种情况下提高读取性能和查询性能例如 ● 重复查询需要另一个集合中的大型文档中的一些字段。您可以选择在重复查询目标集合的嵌入文档中维护这些字段的副本以避免合并两个不同的集合或执行频繁的 $lookup 操作。 ● 经常需要集合中某些字段的平均值。您可以选择在单独的集合中创建派生字段该集合作为写入的一部分进行更新并维护该字段的运行平均值。 虽然嵌入没有重复数据的文档或数组是对相关数据进行分组的首选但当必须维护单独的集合时非规范化可以提高读取性能。 单个文档可以代表整个客户订单或特定太阳能电池板一天的能源产量。一些来自关系数据库、更熟悉规范化数据库模型世界的用户将文档视为表中的一行或分布在多个表中。虽然没有什么可以阻止您以这种方式构建架构但这并不是存储数据或查询大量数据尤其是 IoT 数据的更有效方法。 与关系数据库的规范化数据库模型相比非规范化使您能够提高数据库性能同时减少连接。 尽管 MongoDB 支持副本集从版本 4.0 开始和分片集群从版本 4.2 开始的多文档事务但对于许多场景非规范化数据库模型将继续最适合您的数据和用例。 请注意对于非规范化数据库**保持一致的重复数据非常重要。**然而在大多数情况下数据检索性能和查询执行的提高将超过数据冗余副本的存在以及避免数据不一致的需要。 附录二数据库非规范化与数据库规范化相比何时有意义 **当读写比率较高时非规范化就有意义。**通过非规范化您可以避免昂贵的连接但代价是进行更复杂和更昂贵的更新。因此您应该仅对那些最常读取且很少更新的字段进行非规范化因为数据冗余不是什么问题。 lookup 操作根据指定字段连接同一数据库中两个集合的数据。当您的数据结构类似于关系数据库并且您需要对通常分布在多个表中的大型分层数据集进行建模时$lookup 操作可能会很有用。但是这些操作可能很慢并且占用大量资源因为它们需要在两个集合而不是单个集合上读取和执行逻辑。 如果您经常运行 $lookup 操作请考虑通过非规范化重组您的架构以便您的应用程序可以查询单个集合来获取它需要的所有信息。使用嵌入文档和数组来捕获单个文档结构中数据之间的关系。使用数据库非规范化来利用 MongoDB 的丰富文档模型这允许您的应用程序在单个查询执行中检索和操作相关数据。 通常对于操作数据库来说采用数据库非规范化是最有利的——在单个操作中读取或写入整个记录的效率超过了存储需求的任何适度增加。 标准化数据模型使用文档之间的引用来描述关系。一般来说在以下场景中使用标准化数据模型 ● 当嵌入会导致数据重复但无法提供足够的读取性能优势来抵消数据重复的影响时。 ● 表示更复杂的多对多关系。 ● 对大型分层数据集进行建模。 如今市场上有各种各样的数据库设计选项。关系数据库模型和数据库规范化的实践有其优点和局限性。跨表执行联接操作的需要会影响性能、抑制扩展并带来技术和认知开销。开发人员经常在数据库中创建变通方法以实现效率优势。那些基于高性能关系数据库的应用程序通常会结合临时非规范化、物化视图和外部缓存层以克服规范化关系数据库的限制。
http://www.sczhlp.com/news/238766/

相关文章:

  • 白云区做网站网红营销分析
  • 贵阳中企动力做的网站网站新闻稿模板
  • 深圳网站制作必推祥奔科技网站建站外包公司
  • 通辽企业网站建设百度下载安装2022最新版
  • AI开发微信小程序-有感
  • 周康阳精选冲刺省选国赛思维训练题
  • 丽江电子商务网站建设采集更新wordpress
  • 最超值的手机网站建设如何提高自己的营销能力
  • 做印刷在哪个网站接单好好网站页面效果图怎么做的
  • 行业 专业 网站建设中国企业黄页信息网
  • 织梦网站最新漏洞入侵网站模块添加
  • 杭州专业建设网站哪里好中国网站建设代理项目
  • python进行网站开发有哪些可以做推广的网站
  • 建湖做网站的网站模板编号
  • 奉贤做网站公司优质的武进网站建设
  • 自己做网站好做么北京百度关键词排名
  • 广州本地做网站wordpress主题商店
  • 论坛推广网站重庆企业网站建设官网
  • 网站诊断与检测用asp.net和access做的关于校园二手网站的论文
  • 营销型网站设计官网关键词优化师
  • 关于网站开发的个人小结浙江大境软装设计
  • 网站建设和托管哪家好爱站网关键字查询
  • 网上网站建设教程高端网站开发环境
  • 牛什么的网站建设seo软件优化工具软件
  • DW做旅游网站毕业设计模板深圳vi设计公司排行
  • 网站托管费用多少iis网站伪静态
  • 什么官网比较容易做网站戏剧节宣传推广方案
  • dw做网站环境配置广告设计专业术语
  • 做网站对外贸有什么用合肥建站公司seo
  • 网站制作 p广州市用工备案在哪个网站做