【问题标题】:quickest sparse matrix access, when disk is involved涉及磁盘时最快的稀疏矩阵访问
【发布时间】:2014-09-09 15:06:59
【问题描述】:

假设您有一个包含 10 个 Mio 记录的表“用户”和一个包含 1 个 Mio 记录的表“组”。平均而言,每个组有 50 个用户,我至少将它们存储在一个名为 users2groups 的表中的 rdbms 中。 users2groups 实际上是一个稀疏矩阵。只有 80% 的用户和组完整数据集适合可用内存。组成员 (users2groups) 的数据位于顶部,因此如果需要内存来缓存组成员,则必须从用户表或组表或两者中释放内存。

我希望能够:

  • 按名称快速查找用户并
  • 按名称快速查找组和
  • 快速获取组中的所有用户并且
  • 快速获取用户所属的所有组

根据我的经验,磁盘延迟在很大程度上决定了您的访问速度。您还可以在读取和写入速度之间取得平衡。然而,在这之前,必须先决定一种数据库类型……例如:

  • 关系型 DBMS
  • 键值对存储
  • 文档存储
  • RDF 商店
  • 面向对象的 DBMS
  • 图形数据库管理系统
  • 搜索引擎
  • 多值 DBMS
  • 本机 XML DBMS
  • 宽列存储
  • 内容商店
  • 导航 DBMS
  • (压缩)位图
  • 文件
  • 更多...?

所以问题是,当 RAM 容量低于考虑稀疏矩阵的可用数据时,所有这些系统中的哪一个或哪些组合可提供最佳的整体读取访问性能(具有可接受的写入访问性能)? ...以及如何在所选技术中平衡所有三个实体/表的内存利用率...?

由于这是一个概念性问题,磁盘空间和 CPU 容量超出范围或被视为“无限期”可用。

顺便说一句。我知道,通过使用基于哈希的索引(例如 crc32(lower(STRING))),可以有效地加快搜索用户名或组名等名称的速度 - 一个示例 select 会比这样:select somethinguseful from name=SEARCHSTRING 和 hash=crc32(lower(SEARCHSTRING)) 的用户。然而,当我说用户和组表有 80% 的 RAM 覆盖率时,哈希和它们的索引还没有包含在内存中。那是因为我不清楚,如果没有更好的集成解决方案。目前我只是假设,将整个主题分成用户、组和用户组三​​个部分是最明智的。我这里缺乏证据。

-------- 更新 -------------- ------------

我了解桌面上存在相互竞争的概念:

  • 对非规范化进行了扩展,在这种情况下,我可以处理非常少的磁盘查询集。 (例如 mongodb 等)
  • 压缩数据以使大部分数据无论如何都适合内存(例如压缩位图)

由于非规范化意味着:“增加数据量”,这两个概念似乎相互矛盾。是否有最佳实践或科学或明智的论据,何时使用非规范化以及何时使用挤压数据方法?例如。一个 KPI 说:如果小于 80% 适合内存,就去非规范化吧?

-------- 更新 -------------- ------------

额外的内存需要额外的钱,大多数数据库服务器通常都有很多空磁盘空间,让他们感到厌烦。所以非规范化很便宜。另一方面,非规范化机会是有限的:磁盘延迟在物理上限制了每秒最大查询量,句号。太多对磁盘的查询被排队,这将非规范化限制为具有大量流量的应用程序的扩展。即使是非规范化的数据访问速度也很大程度上取决于内存。

所以也许 KPI 在这里是不可能的。无论如何,对于给定的稀疏矩阵示例,非规范化和压缩数据方法需要如何平衡?我想在压缩用户和组表时,将它们留在 rdbms 中,然后将释放的内存分配给服务于 users2groups 关系的文档数据库的缓存。然而,这引入了一系列新问题,例如处理 2 个数据库系统的多次往返和更复杂的查询管理。那么如何解决呢?

----------- 更新 -----

根据 lagivan 的建议,只有标记关系的稀疏矩阵似乎以一种明智的方式解决:有 2 个表用户和组,然后在表用户中有一个多重 ID 字段,其 ID 与组相关,反之亦然在表中分组多个 ID 字段,其中包含与用户相关的字段。我猜这个解决方案并没有与特定技术紧密耦合。它甚至可以通过 VARBINARY 或任何 blob 在 MYSQL 中实现。

问题的突出部分与包含一些“果汁信息”如状态或 lastupdatedate 的稀疏矩阵有关。因此,使用外键数组会按概念禁用这些信息。因此,这种情况的原始问题仍然悬而未决:当 RAM 容量低于考虑稀疏矩阵的可用数据时,所有这些系统中的哪一个或哪些组合提供最佳的整体读取访问性能(具有可接受的写入访问性能)? ...以及如何在所选技术中平衡所有三个实体/表的内存利用率...?

【问题讨论】:

  • 你能澄清一下 status/lastupdatedate 吗?它与users2groups关系有关吗?所以你想存储用户被添加到组的日期,对吧?
  • 确切地说:lastupdatedate 是关于用户被添加到组的时间。状态可以是数值或 ID,例如。 0 表示“已删除”,1 表示“活动”,2 表示“提议”,3 表示“待确认”。不是针对给定的示例,但通常在稀疏矩阵中可能还需要存储特定的数值或阈值或目标日期。用 RDBMS 术语来说,我会说交叉引用获得了额外的字段。
  • 这些附加要求对设计至关重要。我建议你先写下最常见的用例。设计应该基于这些用例,以便为它们提供最佳性能。例如,问题是您何时想要获取这些日期和状态 - 将它们显示在用户屏幕上还是显示在组屏幕上?它会影响您存储它们的最佳方式。
  • 我不明白这一点。让我们考虑三个字段:1. createddate,2. lastupdateddate,3. Status-ID,如另一条评论所示。在 RDBMS 中,您只需将它们附加到 users2groups 表,然后将它们用于不同的事情 - 例如:仅显示组的活动用户。根据创建时间和用户数量绘制用户增长路径。根据 lastupdateddate 和 status=deleted 绘制一个fluction路径。绘制一组或一组组的波动图。显示最近推荐的前 20 名用户。通常随着时间的推移需求增加......
  • 查看我的更新答案。

标签: bitmap rdbms database-performance graph-databases key-value-store


【解决方案1】:

考虑到您无法将完整的数据集放入 RAM,您无论如何都会面临由 I/O 操作引起的性能问题。因此,您只能依赖缓存和优化的数据结构(db 类型)。此外,我认为您应该选择面向未来的解决方案。我无法涵盖所有​​数据库类型,但我会投票反对 RDBMS,因为拥有稀疏矩阵 users2groups 应该是相当低效的。以下是一些选项:

  1. 如果您非规范化 users2groups 关系,特别是如果您使用分片来使用多个服务器将用户和组放入内存中,文档存储(例如 MongoDB)将是一个很好的解决方案。因此,每个用户文档都将包含组列表,每个组都将包含用户列表。因此,缓存到位后,一旦加载用户记录,您将免费获得组列表。
  2. RDF/Graph 存储也可能是一个很好的解决方案。特别是如果您可以选择使用 SaaS 解决方案,那么扩展将更加容易。例如,我们使用的是 Dydra 图数据库。在这种情况下,无论如何都会对数据进行标准化。
  3. 原生 XML 存储(例如 eXist-db)也可以工作,特别是如果您更喜欢基于模式的数据。在这里,我将应用与文档存储选项相同的非规范化。

最后,我相信魔鬼在细节中。最终的表现将主要取决于您的 DBA 的技能和经验。

更新

考虑到存储更多与 users2groups 交叉引用相关的数据的额外要求,我建议两种选择:

  1. 保持非规范化 users2groups(MongoDB 案例)。考虑到您的用例,我觉得组是管理 users2groups 关系的中心点。您主要需要关于组的统计信息,而不是关于用户的统计信息。然后您应该将关系数据(创建、修改日期、状态)存储在组文档中。无论状态如何,用户文档都将仅包含链接组 ID 的列表。
  2. 拒绝非规范化。在这里,您可以选择图形数据库,或者使用额外的 RDBMS 表或 MongoDB 集合 users2groups。在后一种情况下,您将不得不使用表连接或多个请求 (MongoDB)。当然,与第一个选项相比,它会降低性能。但是,如果您想出更多的关系数据或更复杂的用例,它可能会更有益。

【讨论】:

  • 我更新了我的帖子。 - 你的回答是否暗示要完全改变持久层,或者用户和组表是否仍然存在于 rdbms 中? SAAS 与否对这个问题没有帮助。我很清楚,如果有足够的内存,如何调整数据库。然而,额外的内存需要额外的钱,大多数数据库服务器通常都有大量的空磁盘空间,让他们感到厌烦。所以实际上问题是关于如何利用硬件资源。可能我刚刚从更新中回答了我的 KPI 问题。所以成本与内存饱和度和性能有关 - 如何 KPI 呢?
  • 我只记得成本不是唯一的限制/决策因素。磁盘延迟在很大程度上限制了每秒最大查询量。太多针对磁盘的查询被排队,这将非规范化限制在具有大量流量的应用程序的扩展范围内。
  • 我确实建议彻底改变持久层。考虑到 users2groups 矩阵是稀疏的,反规范化在您的情况下值得做。显然 users2groups 表每个关系需要两个字段,而在非规范化之后,每个关系也将有两个字段,只有它们将存储在相应的用户和组文档中。它只会加快读取操作,但会减慢写入速度。此外,在 MongoDB 的情况下,它大大简化了分片。这与 KPI 无关,而是与您期望系统中的操作频率有关。
  • 我不明白。 “完全改变持久层”和“...users2groups 表...只有它们将存储在相应的用户和组文档中”是否相互矛盾。那么“用户”和“组”表是进入文档数据库还是留在 rdbms 中?
  • 所以你的意思是,操作的数量决定了非规范化的利弊决定?效果如何?我认为您的读取次数越多,您就越需要尝试将数据压缩到内存中(例如压缩 -> 压缩位放大器)......
【解决方案2】:

这针对的是与包含一些“果汁信息”如状态或 lastupdatedate 的稀疏矩阵相关的问题部分。

我试图概括答案的第一部分:实际上我没有找到真正的原因,为什么要从 RDBMS 改为任何其他技术来更好地解决稀疏矩阵。因此,让我们仅考虑 RDBMS(非规范化数据可以存储在 varbinary 或 blob 中)。我是标准化的忠实粉丝。但是我现在学到的是:非规范化,如果考虑到数据和索引数据,非规范化会降低内存消耗。规范化规则旨在优化数据的内存消耗,而没有考虑到诸如稀疏矩阵(带有索引的外键对)之类的场景很容易混淆规范化的好处和努力。我也(重新)了解到,尽可能地将数据压缩到内存中是性能的关键(lagivan 也争论基于缓存的性能杠杆)。

话虽如此,第二部分的答案有多种选择:

来自 Lagivan 的更新 +

  • 为每个“果汁信息”用例拥有自己的总和/跟踪/审核表 - 也就是根据汇总数据及时进行非规范化。
  • 结合非规范化和规范化,其中非规范化仅适用于简单的关系(参见答案的第一部分),而使用“果汁信息”进行规范化的时间范围非常有限(例如三个月)
  • 将“果汁信息”写入任何日志文件,然后偶尔汇总报告(例如,每天一次)——这就是数据仓库的工作

现在的解决方案是计算每个可接受的索引 AND 数据解决方案的内存消耗,然后选择具有最低消耗值的选项。顺便说一句,每个选项都有不同级别的实施工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-05
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 2017-04-21
    • 2016-02-03
    • 2021-12-30
    相关资源
    最近更新 更多