当前位置: 首页 > 科技观察

开始使用MongoDB之前应该知道的14件事

时间:2023-03-22 00:50:06 科技观察

在开始使用MongoDB之前你应该知道的14件事同样,在设计模式和访问模式时设计索引。避免大对象,尤其是大数组。小心您的MongoDB设置,尤其是在安全性和稳定性方面。MongoDB没有查询优化器,因此您必须注意如何对查询操作进行排序。我使用数据库很长时间了,但最近才开始使用MongoDB。在开始使用MongoDB之前,我希望知道一些事情。作为一般经验法则,人们对数据库是什么以及它们能做什么有先入为主的想法。为了其他人的方便,本文列出了一些常见的错误。在没有身份验证的情况下创建MongoDB服务器不幸的是,默认情况下,MongoDB安装时没有启用身份验证。在仅本地访问的工作站上,这很好。然而,由于MongoDB是一个多租户系统,它会使用尽可能多的内存,因此最好安装在内存最大化的服务器上,即使是用于开发工作。在不启用身份验证的情况下使用默认端口在服务器上安装是自找麻烦,尤其是当可以在查询中运行任意JavaScript时(例如,使用$where作为注入攻击的向量)。有多种身份验证方法,但用户ID/密码凭证是最容易安装和管理的。当您考虑基于LDAP的身份验证时,可以采用该方法。当我们谈论安全性时,MongoDB必须保持最新,并且始终值得在日志中寻找未经授权访问的迹象。我不喜欢使用默认端口。忘掉限制MongoDB的攻击面吧MongoDB的安全清单为降低网络渗透和数据泄露的风险提供了很好的建议。人们很容易认为开发服务器不需要高级别的安全性。并非如此:安全性对所有MongoDB服务器都很重要。特别是,除非您有充分的理由使用mapReduce、group或$where,否则您应该通过在配置文件中设置javascriptEnabled:false来禁用JavaScript。因为标准的MongoDB数据文件没有加密,所以使用专门的用户来运行MongoDB也是明智的。对数据文件的完全访问权限仅限于该用户,因此您可以使用操作系统自带的文件访问控制。不设计模式MongoDB不强制执行模式。这并不是说它不需要架构。如果您真的想保存文档并且您没有一致的模式,您可以非常快速和轻松地保存它们,但检索可能很麻烦。《MongoDBSchema设计的六大点赞原则》是一篇值得一读的经典文章,第三方工具(如Studio3T)提供的“SchemaExplorer”等功能也很值得一读,它们可以执行定期的Schema检查。值得拥有。与任何其他错误配置相比,忘记排序规则(排序顺序)会导致更多的挫败感和浪费时间。MongoDB默认使用二进制排序规则。这对任何地方的文化都不利。在80年代,区分大小写、区分重音和二进制排序规则与念珠、长袍和卷曲胡须一起被视为奇怪的时代错误。现在,他们没有借口了。现实生活中motorbike和Motorbike是一样的,Britain和Britain是同一个地方。小写和大写字母仅是书面等价物。不要再让我谈论重音字符排序规则了。创建MongoDB数据库时,请使用适合系统用户的语言和文化的区分重音、区分大小写的排序规则。这使得字符串数据的检索更加容易。创建大型文档集合MongoDB乐于将最大16MB的文档放入集合中,而GridFS则专为超过16MB的大型文档而设计。但仅仅因为它可以容纳大型文档并不意味着它是个好主意。当单个文档的大小为几KB时,MongoDB表现最佳,将它们更像是宽SQL表的行。大文档会导致各种性能问题。使用大型数组创建文档文档可以包含数组。最好将数组元素的数量保持在四位数以下。如果频繁添加数组,会使包含它的文档太大,因此需要移动它在磁盘上的位置,这反过来意味着必须更新每个索引。当重新索引包含大型数组的文档时,会发生大量索引重写,因为每个数组元素都有一个单独的索引条目。此外,在插入或删除此类文档时会发生这种重建索引。为了尽量减少这个问题,MongoDB有一个“填充因子”,为文档增长提供空间。您可能认为可以通过不索引数组来解决这个问题。不幸的是,没有索引,您还有其他问题。因为文档是从头到尾扫描的,所以找到数组末尾附近的元素需要更多时间,并且大多数处理文档的操作都会变慢。忘记聚合情况下的阶段排序在具有查询优化器的数据库系统中,您编写的查询说明您想要什么而不是如何获得它。这就像在餐厅点餐;您通常只是点菜而没有向厨师提供详细说明。在MongoDB中,您正在指导Chef。例如,你需要使用$match和$project来确保管道中的数据尽早减少,数据减少时排序只发生一次,并按照你想要的顺序进行查找。查询优化器为您节省了不必要的工作,优化阶段顺序,选择连接类型,它会宠坏你。MongoDB为您提供了更多控制权,但这种便利是有代价的。Studio3T等工具可以更轻松地构建准确的MongoDB聚合查询。其聚合编辑器功能允许您一次在一个阶段应用管道运算符,并且您可以在每个阶段验证输入和输出,从而使调试更加容易。使用快速写入永远不要将MongoDB设置为低稳定性高写入。看起来“file-and-forget”模式使写入速度更快,因为命令在实际写入任何内容之前返回。如果系统在数据写入磁盘之前崩溃,数据就会丢失,从而存在不一致状态的风险。幸运的是,64位MongoDB启用了“Journaling”。MMAPv1和WiredTiger存储引擎都使用日志记录来防止上述情况,但是如果关闭日志,WiredTiger也可以在恢复过程中恢复到最后一个一致的检查点。日志可以保证数据库在恢复时处于一致的状态,写入日志时会保存所有的数据。可以使用运行时选项commitIntervalMs配置日志写入之间的间隔。为确保写入,请确保在配置文件(storage.journal.enabled)中启用了日志功能,并且提交间隔与您可以承受的数据丢失量相对应。无索引排序在搜索和聚合中,您通常希望对数据进行排序。希望在过滤结果后的最后阶段完成,从而减少需要排序的数据量。即使那样,您也需要一个可以覆盖排序的索引。单个键索引或复合索引都可以。当没有合适的索引可用时,MongoDB不得不在没有索引的情况下进行排序。排序操作中所有文档的总大小有32MB的内存限制,如果MongoDB达到这个限制,它要么产生错误,要么有时只返回一个空记录集。LookupwithoutindexsupportLookup的作用类似于SQL联合查询。为了获得良好的性能,需要在键值上建立索引作为外键。这并不明显,因为在explain()中没有报告它的使用。这些索引不包含在explain()记录的索引中,这些索引在出现在管道开头时由管道运算符$match和$sort使用。索引现在可以覆盖聚合管道的任何阶段。无需多行更新db.collection.update()方法用于修改部分或全部现有文档,或完全替换现有文档,具体取决于您提供的更新参数。它不会更新集合中的所有文档,除非您设置multi参数以更新符合查询条件的所有文档。这一点不是很明显。忘记哈希对象中键顺序的含义在JSON中,对象包含零个或多个名称/值对的无序集合,其中名称是字符串,值是字符串、数字、布尔值、空值、对象或大批。不幸的是,BSON在进行搜索时赋予了顺序意义。在MongoDB中,嵌入对象中键的顺序很重要,即{firstname:"Phil",surname:"factor"}和{surname:"factor",firstname:"Phil"}不会匹配。这意味着如果要确保可以找到它们,则必须保留文档中名称/值对的顺序。混淆“null”和“undefined”根据官方JSON标准(ECMA-404第5节),“undefined”值在JSON中从未合法,尽管它实际上在JavaScript中使用。此外,它在BSON中被“弃用”,将被转换为$null,这并不总是令人满意的解决方案。在MongoDB中,避免使用“undefined”。使用$limit()而不是$sort()通常,当您在MongoDB中进行开发时,仅查看查询或聚合返回的结果示例很有用。$limit()可以满足这个要求,但是,除非您首先使用$sort,否则它永远不会出现在您的代码的最终版本中。这是因为,如果不这样做,您将无法保证结果的顺序,也无法可靠地“翻阅”数据。为确保可靠性,查询或聚合必须是“确定性的”,即每次执行它们都会给出相同的结果。包含$limit但不包含$sort的代码不是确定性的,以后可能会导致难以跟踪的错误。总结对于MongoDB,您最终会感到失望的唯一方式是将它直接与另一种类型的数据库(如RDBMS)进行比较,或者对它抱有特殊期望。这就像将橙子与叉子进行比较。数据库系统有它们的用途。最好理解并欣赏这些差异。强迫MongoDB开发人员以RDBMS的方式做事是一种耻辱,我希望继续看到有趣的新方法来解决老问题,例如确保数据完整性和使数据系统能够从故障和恶意损坏中恢复。在4.0版本中,MongoDB引入了ACID事务处理,这是以创新方式引入重大改进的一个很好的例子。多文档、多语句事务现在是原子的,这允许开发人员调整用于获取锁、使挂起的事务过期和修改隔离级别的时间。