我是否将Azure表存储或SQL Azure用于CQRS读取系统?

时间:2012-07-09 08:26:16

标签: azure azure-sql-database azure-storage cqrs azure-table-storage

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

我们数据的简化结构是:

  • 用户
  • 对话(将邮件分组给相同的收件人)
  • 消息
  • 收件人(用户集)

我想将其转换为非规范化状态,以便当用户请求查看从EITHER读取的消息提要时:

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

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

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

  • 对话详细信息,消息和收件人的不同表格
  • 存储在“对话”表中的邮件和收件人的分区键。
  • 酒吧;这遵循与上面相同的结构
  • 绕过最大行大小问题
  • 但是规范化状态是否会降低非规范化表的性能增益?

OR

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

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

我要问的是,是否有人在Table Storage或SQL Azure中实现非规范化结构,您会选择哪种?还是有一种我错过的更好的方法?

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

3 个答案:

答案 0 :(得分:9)

考虑使用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提供的更多存储时,使用Azure表通常是有意义的(尽管您现在可以使用Federations打破单个数据库的最大存储限制)。例如,如果您需要存储10亿条客户记录,则使用Azure Table可能有意义。但是在我看来,单独使用Azure Table提高速度是相当可疑的。

如果我在你的帮助下,我会非常努力地质疑这一说法,并确保您拥有专业的SQL开发技能,可以证明您在完全更改架构之前已经达到了SQL Server / SQL Azure固有的性能瓶颈。

此外,我会定义您的表现目标。您是否希望访问时间快100倍?您是否考虑过缓存?您是否在数据库中正确使用索引?

我的2美分......:)

答案 1 :(得分:6)

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

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

    为进一步隔离,您可以将读取数据与写入数据物理隔离

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

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

    尽管

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

    关键是

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

    它可以是一个不同的模式,但是仍然可以被规范化,或者至少不能被“高度非规范化”。再次-您可以,但这并不意味着您必须。

    此外,如果由于写锁而不是由于繁重的SQL请求而导致性能不佳:

    读取存储区可以是写入存储区的只读副本

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

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

    “材料化视图” 模式描述了在源数据不适合查询的格式且难以生成合适的查询的环境中生成数据的预填充的视图 ,或者由于数据或数据存储的性质而导致查询性能不佳的地方。

    关键是视图是复数。

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

    ...

    材料化视图通常专门针对一个或少量查询量身定制

    因此您不在这3个选项之间进行选择。实际上,它要宽得多。 同样,您不需要其他存储来创建视图。所有这些都可以在单个DB中完成。

  4. 关于

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

    是的,性能当然会受到损害! (也要考虑一致性问题)。但是,这是否可以,您必须先进行测试才能确定。随着您的数据和您的请求。因为数据传输的延迟实际上可以少于一些精心设计的SQL请求所需的时间。

所以一切归结为:

  1. 您需要哪些功能?表存储和/或 SQL Azure 中的哪些功能?
  2. 然后,要花多少钱?

这些您只能回答自己。这些选择与性能无关。因为这两个指标中都有如果有合适的指标,我认为效果几乎是无法区分的。

总结:

SQL Azure还是Azure表存储?

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

答案 2 :(得分:2)

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

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