大量索引 - MySQL 与 MongoDB - 迁移

Vic*_*llo 5 mysql index mongodb

所以,我从未使用过 MongoDB,我只是阅读了很多关于它的内容,我认为它对我的项目有好处。另外,我对MySQL没有很多经验,说实话,我不知道我要问什么。

设想:

MySQL表profile

  • id = [pk, auto_increment, smallint]
  • user_id = [pk, fk, varchar]
  • category_id = [pk, fk, smallint]
  • role_id = [pk, fk, ti​​nyint]
  • country_id = [pk, fk, smallint]
  • state_id = [pk, fk, smallint]
  • legal_document = [pk, varchar, ?unique]
  • 名称 = [pk, varchar, ?unique]
  • 类型 = [pk,布尔值]
  • last_activity = [pk,日期]

当然,所有fk你看到的都是 MySQL 表。然后我想使用 MongoDB 来存储配置文件信息,profile_info集合应包含如下文档:

{
  '_id' : 1 (profile_id),
  'address': 'Some street in some state of some country :P',
  'phone': [5555555, 5555555],
  'email': 'example@example.com',
   etc...
}
Run Code Online (Sandbox Code Playgroud)

我打算使用 mongodb,因为我的项目需要尽快公开,我们可能会添加几个新的配置文件信息和其他内容,我不想更改表并从具有大量行的工具迁移。

话虽如此,我们可能不得不pk在MySQL表中添加更多的s,所以我正在考虑将所有项目迁移到MongoDB,我不知道这是不是一个好举措。

问题:

  • 最好将pks保留在 MySQL 中,将琐碎信息保留在 MongoDB 中,或者如果我将所有内容都移到 MongoDB 中会好吗?

  • 如果我只是迁移整个项目,但我保持这样的结构,MongoDB 会更快吗?我的意思是喜欢拥有profileprofile_info收藏,而不仅仅是profile.

  • 我担心 MongoDB 可以为具有这么多索引的“表/集合”使用多少资源,我想将磁盘空间和内存保持在最低限度。MySQL 和 MongoDB 之间有重要区别吗?

PS:系统中将使用SSD。

PS II:所有表都只是计划,还没有写。我是一个非常有计划的人,所以请耐心等待。

Mar*_*erg 7

鉴于您的描述,我强烈建议不要使用 MongoDB。不是因为这必然是一个糟糕的选择(尽管我认为出于纯技术原因之外的原因,这对您来说是一种情况)。

以下是引起我注意的要点。

数据建模

除了最微不足道的用例外,尝试将 MongoDB 与关系数据模型一起使用而没有任何调整几乎总是会导致眼泪和痛苦。这就是故事的更好结局。更糟糕的结局是赔钱,可能是大赚一笔。

这样做的原因是,使用 SQL,您可以识别您的实体及其属性和关系,然后用头撞墙几个小时,让左上角超出 JOINS 的右侧,从而让您从用例中得出的问题得到解答. 同时避免像魔鬼圣水一样的数据冗余。

使用 MongoDB 进行数据建模的工作方式有所不同。您确定用例和从中派生的问题,并以某种方式对数据进行建模,以便以最有效的方式回答这些问题。

由于这有点抽象,让我给你一个

例子

让我们假设您有一个名为“chirper”的 Web 应用程序,用户执行 chirps。使用 SQL,您现在可以为您的数据建模,提出类似于用户表和 chirp 表的内容。

您遇到的第一个用例是,您希望在应用程序主页上显示最新的 10 条啁啾声以及啁啾者的用户名。使用 SQL 很容易,您可以对 chirps 和用户进行连接,按数据降序对结果进行排序并限制为 10 条记录。

使用 MongoDB,您可以仔细查看您需要的内容。由于各种原因,您不想将 chirps 嵌入用户集合中。但是由于您确实需要将 chirps 与用户相关联,因此您决定按用户名这样做,并为您的 chirps 集合提出一个“模式”,如下所示:

{
  _id: ObjectId("570b87a56931b8f21a8bf25c"),
  user: "jdoe",
  date: ISODate("2016-04-11T11:17:08.415Z"),
  text: "Chirp!!!"
}
Run Code Online (Sandbox Code Playgroud)

而且,奇迹般地,你所要做的就是做一个

db.chirps.find({}).sort({date:-1}).limit(10)
Run Code Online (Sandbox Code Playgroud)

它以相对便宜的磁盘空间为代价,在没有 JOINS 的情况下为您提供相同的结果。

资源限制

我想将磁盘空间和内存保持在最低限度

MongoDB 很多,但肯定不是资源友好的。它从来就不是 MySQL 的替代品——顺便说一下,它是专门设计为一个相对轻量级的通用 RDBMS。我强烈建议不要出于生产目的在同一台服务器上运行 MongoDB 和其他任何东西。原因是多方面的,但这里是最重要的:

  1. MongoDB 将占用多达 85% - 90% 的可用物理 RAM。这是因为工作集(索引和数据的子集)保存在 RAM 中。
  2. 根据您用于 MongoDB 的存储引擎及其配置,甚至 CPU 利用率也可能相当可观。
  3. 一个负载很重的 MongoDB 需要大量的磁盘 IO。我曾见过 RAID0 中带有 SSD 的系统,其中 IO 速率已达到极限。

暂时忽略这些细节,这意味着在您最不想要它的情况下(您的应用程序正在起飞并且拥有大量用户),MongoDB 将与应用程序的其他部分争夺资源。

不要误会我的意思:MongoDB 本身并不是一个消耗资源的怪物。但是,如果它按照预期的方式进行,即处理大量数据和数据更改,您就不希望应用程序的各个部分争夺资源。

话虽如此:有一些方法可以限制 MongoDB 的资源分配并确保遵守这些限制。可能迄今为止最广为人知的是 Docker。您必须决定在 Docker 容器中运行 MongoDB 是否值得。

至于数据文件大小:默认的wiredTiger存储引擎有透明压缩可用。您可以选择snappy(默认)或更广为人知的zlib压缩。如上所述,两者都以更高的 CPU 利用率为代价。

上市时间

原谅我,但你表现出缺乏关于 MongoDB 的基本知识。由于您不确定该怎么做,因此您能做的最好的事情就是仔细研究每一步,做出决定,冲洗并重复。而且我什至没有考虑到您需要重构数据并且很可能对应用程序持久层进行大量更改。如果我是你并且想要/需要快速上市,我会选择我现在拥有的。如果在生产过程中出现问题,我会让自己成为一名专门研究 NoSQL 的顾问,以找出各种 NoSQL 数据库中的一个是否适合您的需求,确定所述 DBMS(可能是也可能不是 MongoDB),让自己成为专家然后才进行迁移。有专家在您身边。

行政

人们常犯的一个错误是,他们认为管理 MongoDB 部署和让它工作一样容易。它不是。任何 DBA、Sysadmin 甚至 DevOps(即使在最错误的意义上使用)都应该能够运行分片集群。选择合适的维度、识别问题、决定何时缩放、处理重要的问题和错误?没那么多。请注意,后者是高度主观的,并且容易受到所讨论的 DBA 技能的影响。您真的想将生产数据存储在您几乎不了解的系统上吗?

结论

恕我直言,MongoDB 不符合您所说的要求。现在改变很可能会增加您的上市时间,而且非常重要,因为您不了解 MongoDB 的复杂性和陷阱。在最坏的情况下,您会累积技术债务,同时降低应用程序的性能。

MongoDB 不太适合您的资源限制要求,并且找到资源限制的最佳点以提供可接受的性能需要有经验的 DBA 和相当长的时间,在此期间您的应用程序可能会以低于标准的性能运行。

让我把它放在一些上下文中:MongoDB 可能非常适合您的用例,甚至是 excel。但鉴于您的知识水平和规定的要求,我认为目前更改您的持久性技术是不可行的。


MDC*_*CCL 5

我认为在决定使用哪种工具来开发项目之前,您需要考虑多个(非常重要的)方面。

主要目标应该是按原样管理相关数据,这是一项非常宝贵的组织资产,实现所述目标的可靠方式是通过有可靠理论支持的技术手段。

在这方面,值得一提的是,确定数据库的成功不仅取决于选择的数据库管理系统 (DBMS),还取决于许多因素,例如:

  • 其逻辑模型
  • 其物理实现设置
  • 其合格的管理

由于您正在考虑将 SQL 平台作为临时 DBMS,这一事实表明您打算实现关系数据库,因此我将在本答案中重点关注这方面。

尽管EF Codd 博士图灵奖获得者)早在 1970 年就发表了他的开创性论文A Relational Model for Large Shared Data Banks,但我确实认为他的杰出工作仍然是无与伦比的和最先进的,因为例如,牢固地基于一阶逻辑集合论

在 SQL 平台中实现时,设计良好的数据库可以获得关系理论提出的许多优点。相比之下,设计不当的数据库很容易失效。话虽如此,重要的是要意识到关系数据库的开发需要对感兴趣的特定业务领域有深刻的理解。因此,您必须对所有关注的事物进行分析和分类,而这些任务需要强大的数据建模技能。这样,如果您对业务上下文有清晰的认识和良好的建模能力,您将能够创建一个强大的逻辑数据库结构,该结构精确地表示业务上下文,并且易于扩展和修改。

一旦你开发了一个稳定的数据库(考虑到你决定使用的 DBMS 的细节)并启动了你的系统,就该集中精力管理服务器,正如人们所期望的那样,管理数据,这里是其中数据库管理技能尤为重要。

因此,如您所知,所有这些都需要一定的经验,而您只能通过开展多个项目来获得这些经验,最好在专业同事或团队的监督下进行。

需要考虑的方面

因此,为了做出明智的决定,您应该:

  • 继续问好问题。
  • 花时间学习关系理论。
    • 对此,我强烈推荐Dr. Codd bibliography,让你直接向关系范式的鼻祖学习。
  • 增强您的数据建模技能。
    • 您可能会发现感兴趣的IDEF1X。它是一种强大且富有表现力的技术,于 1993 年被美国国家标准与技术研究院 (NIST) 定义为标准。
    • 在这篇元文章中,我讨论了一些基本的建模点,在这个答案中,我处理了一个基本的数据库结构,以防您有兴趣。
  • 评估与 MySQL 相关的功能和限制。
  • 评估其他 SQL 系统并将它们与 MySQL 进行比较。
    • 值得注意的是,各大平台多年来(甚至几十年)都进行了大量优化。
    • 有不同的开源替代方案非常有趣。
  • 研究可用的不同 SQL 方言。
  • 按照理论规定获得 SQL 实践经验,以便您可以在行动中看到它们的价值。
  • 找出作为 MongoDB 基础的理论。
  • 研究类似于 MongoDB 的工具。
  • 将 MongoDB(和其他类似工具)与 SQL 软件(以及前关系技术)进行比较。

Profile 表主键定义和索引

您的问题以特定方式引起我注意的一个部分是您将profile表的所有列定义为 PRIMARY KEY,您在以下评论中对此进行了解释:

[...] 是的,它们是主键,我制作它们pk是因为据我所知,这使它们成为索引并可以加速该表上的 SELECT 操作。我的意思是我们可能需要向表中添加更多索引 ( pk) profile。我已经读过,用很多行做 ALTER 表可以持续很长时间并且可能很复杂,我也喜欢做分片或任何可能有助于提高性能的技术。

因此,有一些关于关系键和索引结构的基本(且非常相关)点需要澄清。

主键

A PRIMARY KEY(PK) 代表一个逻辑元素,它是一个列(或列的组合),其中包含唯一标识相应表中给定行的值。一张桌子不能设置多个 PK。

物理层面上,PK 通常有一个下属INDEX,除了加快数据检索(正如您正确提到的)之外,还有助于确保确定行的唯一性(如此说INDEX,实际上,UNIQUE)。

备用键

一张表可以有一个或多个ALTERNATE KEYs(AK),它们也是逻辑组成部分。AK 是一列(或列的组合),它保留唯一标识相应表中某一行但未被选为 PK 的值。

AK 可以通过 a 建立UNIQUE CONSTRAINT,这通常由物理 辅助INDEX,可提高检索速度并自然地保护行唯一性。

不属于(或不属于)主键或备用键定义的列上的索引

INDEXed如果这种方法可以加速您的某些查询,那么不属于(或不属于)PK 或 AK 的列也可以是。因此,您不需要向 PK 添加新列以获得物理优势,您只需要将它们合并到一个复合非唯一INDEX(或INDEX在必要时为每个相应的列创建一个非唯一)不将它们添加到 PK,因为这样做您将失去其上下文含义的 PK 定义。

实体类型、键和含义

如果在给定上下文中涉及的人已经确定某种事物,即实体类型具有组织意义,那么所述实体类型的每个实例必须通过一个(或多个)的值(或值)来区分它的属性,因此 PK 和 AK 是数据的基本质量,它们完全取决于语义方面。每个实体类型都应该设置为数据库结构中的一个表;每个实体类型实例都应该INSERTed作为相应表中的一行。

因此,我认为有必要声明,就像在服务器内创建数据库和表并不一定意味着此类数据库和表是相关的,将列标记为并不一定意味着它们实际上是键。因此,由于键是数据的内在特征,它们的识别取决于建模者的能力,并且它们在服务器中的正确实现取决于建模者的正确声明。

逻辑和物理

如您所见,区分逻辑元素和物理元素非常重要。综上所述,逻辑(或抽象)组件直接取决于数据的含义;相比之下,物理(或具体)构造是一种在“幕后”使用的机制,以便 DBMS 可以——例如——促进数据检索、支持数据库创建者所做的逻辑定义,或两者兼而有之。

基表和派生表(或关系)

使用 SQL 系统,您可以定义塑造数据库结构的表(通过 DDLCREATE TABLE语句),但这还不是全部,因为一旦需要检索结果集,您还可以获得多个派生表它结合了来自不同表的列,例如,凭借所述表的SELECT语句JOINs。您可以将所述派生表定义为VIEWs,并在必要时直接查询它们。这只是 SQL 平台提供的多功能性的一个很好的例子,因为您将始终使用相同类型的结构,即表(或关系)。

当然,您也可以利用内置的服务器功能进行不同类型的计算、创建计算列和连接列、获取统计信息并继续创建您在设计时甚至无法想象的查询。

如果随着时间的推移,数据用户定义了新的感兴趣的上下文事物,您可以通过向数据库添加新表来完美满足他们的需求,是的,您可以以前存在的表与结合起来,并产生全新的派生关系.

如您所见,关系方法提供的可能性是巨大的

加入

由于JOINs可能看起来有点麻烦,如果您遇到特定查询的问题,您可以来 DBA.SE寻求帮助。有大量用户非常熟练和经验丰富,而且很可能不止一个用户愿意提供他们宝贵的帮助。

对此,应该说这种操作已经被多个SQL厂商在物理层面进行了高度优化。因此,在合适的条件下(即在设计良好的数据库中执行)JOINs绝对是快速的

冗余

关系数据库存储关于现实世界事实的断言,并且一个确切的事实只发生一次。因此,从逻辑的角度来看,多次存储相同的事实是不合理和不必要的。

冗余最终会导致不一致。例如,假设:

  • 有人在某个数据库中两次保留了同一条信息。
  • 后来,其他人来了,UPDATEs只有一次重复。因此,另一个事件不再是最新的。
  • 相继,另一个人UPDATEs出现了至今没有被修改的情况。以这种方式,两个副本在不同的时间点都经历了不同的变化。
  • 然后,当有人对检索有问题的信息感兴趣时,他或她可以找到它的两个不同版本

所以:

  • 哪个版本可以被认为是正确、可靠的?
  • 哪一个准确反映了现实世界?

如您所知,这种现象甚至会产生法律影响,这种情况肯定非常重要。

此外,处理此类不一致(可能通过某种更新同步)所必须花费的时间和精力应该更好地用于为您的组织实际产生价值的任务。因此,我建议通过设计避免存储它们并保持数据库的逻辑一致性完好无损。

具有大量行的表

有多个数据库实例在众多表中保留了数十亿行,它们以非常高的速度为用户提供服务,但这同样是合格从业者进行适当设计的结果。因此,问题不在于存储的信息量,而在于管理所述信息的方式。

多个应用程序使用同一个数据库

关系数据库旨在同时为多个应用程序提供服务。因此,您可以拥有例如一个或多个 Web 应用程序、一个或多个桌面应用程序和一个或多个移动应用程序,所有这些应用程序都可以同时与您的数据库协同工作。

所以-使用编程jargon-必须确保不夫妇与任何应用程序的代码的数据库; 将每个软件组件与其他组件分开,但同时保持连接。