33

我们即将在内部实施 CQRS 系统的读取部分,目标是大幅提高我们的读取性能。目前,我们的读取是通过一个 Web 服务进行的,该服务对规范化数据运行 Linq-to-SQL 查询,涉及从 SQL Azure 数据库进行一定程度的反序列化。

我们数据的简化结构是:

  • 用户
  • 对话(将消息分组到相同的收件人)
  • 信息
  • 收件人(一组用户)

我想将其移至非规范化状态,以便当用户请求查看它从以下任一读取的消息提要时:

Azure 表存储中保存的非规范化表示

  • UserID 作为 PartitionKey
  • 作为 RowKey 的 ConversationID
  • 任何易于更改的易失性数据都存储为实体
  • 在实体中序列化为 JSON 的消息
  • 所述消息的接收者在实体中序列化为 JSON
  • 表存储中一行的大小有限(960KB)的主要问题
  • 此外,对“易失性数据”列的任何查询都会很慢,因为它们不是键的一部分

Azure 表存储中保存的规范化表示

  • 对话详细信息、消息和收件人的不同表
  • 存储在对话表中的消息和收件人的分区键。
  • 禁止那个;这遵循与上面相同的结构
  • 解决最大行大小问题
  • 但是规范化状态会降低非规范化表的性能增益吗?

或者

SQL Azure 中保存的非规范化表示

  • UserID 和 ConversationID 作为复合主键保存
  • 任何易于更改的易失性数据都存储在单独的列中
  • 在列中序列化为 JSON 的消息
  • 所述消息的接收者在列中序列化为 JSON
  • 索引和非规范化数据结构的最大灵活性
  • 性能比表存储查询慢得多

我要问的是,是否有人有在表存储或 SQL Azure 中实现非规范化结构的经验,你会选择哪一个?还是我错过了更好的方法?

我的直觉是,表存储中的规范化(至少在某种程度上)数据将是可行的方法;但是我担心执行 3 次查询以获取用户的所有数据会降低性能提升。

4

3 回答 3

22

您考虑 Azure 表的主要驱动因素是极大地提高读取性能,并且根据您在“SQL Azure 中保存的非规范化表示”下的最后一点,在您使用 SQL Azure 的场景中“慢得多”。出于几个原因,我个人觉得这非常令人惊讶,并且会要求详细分析这种说法是如何提出的。我的默认立场是,在大多数情况下,SQL Azure 会快得多。

以下是我对这一说法持怀疑态度的一些原因:

  • SQL Azure 使用原生/高效的 TDS 协议返回数据;Azure 表使用 JSON 格式,更详细
  • 只要您在 SQL Azure 中使用主键或有索引,SQL Azure 中的联接/过滤器就会非常快;Azure 表没有索引,连接必须在客户端执行
  • Azure Tables 返回的记录数限制(一次 1,000 条记录)意味着您需要实现多次往返以获取许多记录

尽管您可以通过创建包含自定义索引的附加表来伪造 Azure 表中的索引,但您有责任维护该索引,如果您不小心,这将减慢您的操作并可能创建孤立场景。

最后但并非最不重要的一点是,当您试图降低存储成本(它比 SQL Azure 便宜)以及需要比 SQL Azure 提供的更多存储时(尽管您现在可以使用联合来打破单个数据库最大存储限制)。例如,如果您需要存储 10 亿条客户记录,则使用 Azure Table 可能有意义。但在我看来,仅使用 Azure Tables 来提高速度是相当可疑的。

如果我站在你的立场上,我会非常质疑这种说法,并确保你拥有专业的 SQL 开发技能,可以证明你在完全改变你的架构之前已经达到了 SQL Server/SQL Azure 固有的性能瓶颈。

此外,我将定义您的绩效目标是什么。您是否希望访问速度提高 100 倍?您是否考虑过缓存?您是否在数据库中正确使用索引?

我的 2 美分... :)

于 2012-07-09T13:26:23.127 回答
7

我不会试图争论CQRS的确切定义。当我们谈论Azure时,我将使用它的文档作为参考。从那里我们可以发现:

  1. CQRS不需要您使用单独的读取存储。

    为了更好地隔离,您可以将读取数据与写入数据物理分离。

    “你可以”并不意味着“你必须”。

  2. 关于非规范化和读取优化:

    虽然

    基于CQRS的系统的读取模型提供数据的物化视图,通常作为高度非规范化的视图

    关键是

    读取数据库可以使用自己的数据模式,该模式针对查询进行了优化

    它可以是不同的模式,但它仍然可以被规范化或至少不是“高度非规范化”。再说一遍——你可以,但这并不意味着你必须。

    不仅如此,如果你的性能是由于写锁而不是因为繁重的 SQL 请求而导致的:

    读存储可以是写存储的只读副本

    而当我们谈request的优化时,最好多谈request本身,少谈存储类型。

  3. 关于“它从任何一个读取” [...]

    物化视图模式描述了在源数据不适合查询的格式、难以生成合适的查询或由于数据或数据的性质而导致查询性能较差的环境中生成数据的预填充视图店铺。

    这里的关键是观点是复数的。

    物化视图甚至可以针对单个查询进行优化。

    ...

    物化视图往往专门针对一个或少量查询

    所以你的选择不在这三个选项之间。它实际上要广泛得多。同样,您不需要其他存储来创建视图。所有这些都可以在单个数据库中完成。

  4. 关于

    我的直觉是,表存储中的规范化(至少在某种程度上)数据将是可行的方法;但是我担心执行 3 次查询以获取用户的所有数据会降低性能提升。

    是的,当然,性能会受到影响!(还要考虑一致性问题)。但是在你测试之前你永远无法确定它是否可以。使用您的数据和您的请求。因为数据传输的延迟实际上可能少于某些复杂的 SQL 请求所需的时间。

所以一切归结为:

  1. 您需要哪些功能以及Table Storage和/或SQL Azure具有哪些功能?
  2. 然后,要花多少钱?

这些只能自己回答。而这些选择与性能关系不大。因为如果其中任何一个都有合适的索引,我相信性能几乎无法区分。

总结一下:

SQL Azure 还是 Azure 表存储?

对于不同的请求和数据,您可以并且可能应该同时使用. 但是问题中的信息太少,无法给您确切的答案(我们需要一个确切的要求)。但我同意@HerveRoggero - 很可能你应该坚持使用SQL Azure

于 2020-06-07T14:08:02.287 回答
2

我不确定是否可以为其他答案添加任何价值,但我想提请您注意根据您的查询路径对数据存储进行建模。你要一起查询所有提到的数据位吗?用户是否会在单击或其他内容后要求其中一些作为附加信息?我假设您已经考虑过这个问题,并且您肯定想要一次查询所有内容。即,API 或其他东西需要一次返回所有这些信息。

在这种情况下,没有什么比按键查询单个对象更好的了。如果您专门谈论Azure 的表存储,它就在那里说它是一个键值存储。我很好奇您是否考虑过文档数据库(例如Cosmos DB)?如果您正在实施 CQRS 读取模型,您可以为每个用户生成一个文档,其中包含用户在提要中看到的所有信息。您通过用户 ID 查询该文档,这将是关键。在我看来,这种方法将是最佳的 CQRS 实现,因为毕竟您的目标是实现读取模型。除非我误解了您问题中的某些内容,或者您​​有充分的理由不使用文档数据库。

于 2020-06-15T19:52:34.807 回答