【问题标题】:CQRS and primary key: guid or not?CQRS 和主键:guid 与否?
【发布时间】:2011-10-18 11:11:33
【问题描述】:

对于我的项目,这是一个潜在的大型网站,我选择将命令界面与查询界面分开。因此,提交命令是不返回结果的单向操作。这意味着客户端必须提供密钥,例如:

service.SubmitCommand(new AddUserCommand() { UserId = key, ... });

显然我不能使用 int 作为主键,所以 Guid 是一个合乎逻辑的选择 - 除了我到处读到它对性能的影响,这让我很害怕 :)

但后来我也阅读了关于 COMB Guid 的文章,以及它们如何提供 Guid 的优势,同时仍然具有良好的性能。我还在这里找到了一个实现:Sequential GUID in Linq-to-Sql?

所以在我做出这个重要决定之前:有人有这方面的经验,有什么建议吗?

非常感谢!

路德

【问题讨论】:

    标签: c# performance key guid cqrs


    【解决方案1】:

    您没有指定您使用的数据库引擎,但由于您提到了 LINQ to SQL,我猜它是 MS SQL Server。
    如果是,那么Kimberly Tripp 对此有一些建议:

    用几句话概括两个链接:

    • 顺序 GUID 的性能优于随机 GUID,但仍比数字自动增量键差
    • 为您的表选择正确的聚集索引非常重要,尤其是当您的主键是 GUID 时

    【讨论】:

    • 是的,它是 sql server!但是如果我想使用查询/命令模式,除了使用(连续)guid,我真的有其他选择吗?
    • @Lud:不,你没有,因为你需要在发送命令之前生成 id。如果它可能是大型网站,您肯定需要使用唯一 ID,因为您将来需要分发您的系统。
    【解决方案2】:

    首先,我使用顺序 GUID 作为主键,性能没有任何问题。

    大多数测试Sequential GUID vs INT as primary key 使用批量插入操作并从空闲数据库中选择数据。但在现实生活中,选择和更新发生在同一时间。

    当您应用 CQRS 时,您不会有批量插入,而且打开和关闭事务的负担将比 1 次写入查询花费更多的时间。由于您已分离读取存储,因此您在具有 GUID PK 的表上的选择操作将比在统一存储中具有 INT PK 的表上快得多。

    此外,为您提供消息传递的异步性使您的应用程序可以比具有阻塞 RPC 调用的系统更好地扩展。

    考虑到上述情况,选择GUIDs vs INTs在我看来是一分钱一分货。

    【讨论】:

    • 谢谢。但是,实际上,我不打算使用成熟的 CQRS(请参阅我的另一篇文章:stackoverflow.com/questions/6917843/architecture-simple-cqs)。这会影响您的评论吗?
    • 一点点。无论如何,您将使用 DDD 原则,因此您仍然不会进行批量插入/更新操作。如果您想以异步方式执行插入操作,除了使用 GUID 作为主键之外,您别无选择。当然,这会为数据库产生一些(较小的)性能开销,但能够简单地扩展您的应用程序很重要。
    • 不要忘记保存已处理的消息以便能够迁移到单独的读取存储
    【解决方案3】:

    您可能已经有一个自然键,例如用户名,用于唯一标识用户,而不是向命令提供 Guid(这可能对域没有意义)。这个自然键对用户命令更有意义:

    1. 创建用户时,您知道用户名,因为您将其作为命令的一部分提交。
    2. 当您登录时,您知道用户名,因为用户将其作为登录命令的一部分提交。

    如果您正确索引用户名列,则可能不需要 GUID。验证这一点的最佳方法是运行测试 - 插入一百万条用户记录并查看 CreateUser 和 Login 的执行情况。如果您确实看到您已验证对业务产生不利影响且无法通过缓存解决的严重性能下降,然后添加一个 Guid。

    如果您正在执行 DDD,您将需要专注于保持域清洁,以便代码易于理解并反映实际的业务流程。引入人工密钥与该目标背道而驰,但如果您确定它可以为业务提供实际价值,那就继续吧。

    【讨论】:

    • 这对用户来说是一个有趣的想法;确实,用户名是唯一的。似乎是一个很好的解决方案。您会为具有唯一标题(urltitle)的文章做同样的事情吗? AddCategoryCommand 怎么样,那里的关键是什么?
    • 对于一个类别,我会选择名称。您可能想要制定一个无法更改的 slug,就像这个问题的 URL 的“cqrs-and-primary-key”部分一样。 (我不知道这是否真的是一个蛞蝓——你必须尝试改变问题的标题,看看会发生什么。)
    • 在我的项目中,对于一些命令,我​​需要先执行命令,然后再执行一个查询,得到一个更简洁的标识符。例如,我的订单有一个标识列,但它们也有一个自然键 (customerId, referenceNumber),所以我有一个查询方法,它返回给定 customerId 和 referenceNumber 的订单 ID(标识 int)。
    • 看来我可以更改这篇文章的标题。所以可能这不是关键......
    • 是的,所以 slug 的概念可能仍然是您想要的,但堆栈溢出 url 不是一个很好的例子。 :) 但是,slug 模式肯定在某处使用 - 它只是从文章标题派生的字符串 ID。也许 WordPress 使用它们。概念清晰吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多