我正在研究为数据库行提供主键的这三种主要方法的优缺点.

那么假设我使用的数据库支持这些方法中的一种以上,有没有简单的启发式方法来确定对我来说最好的选项是什么?

如何考虑分布式/多主机、性能要求、ORM使用、安全性和测试等因素?

有没有可能会遇到意想不到的缺点?

推荐答案

UUIDs

除非它们是"以递增的单调顺序"生成的,否则它们可能会对索引造成极大的损害/碎片.对UUID生成的支持因系统而异.虽然可用,但在大多数情况下,我不会使用UUID作为我的primary clustered索引/PK.如果需要,我可能会将其作为次要专栏,可能是索引的,也可能不是.

一些人认为UUID可以用于从任意数量的系统安全地生成/合并记录.虽然UUID(取决于方法)发生碰撞的几率通常非常小,但至少在一些外部输入或very个坏运气的情况下,它有可能产生碰撞.我相信只有true个PK应该在系统之间传输,我认为在大多数情况下,这不是(或不应该是)database-generated UUID.

autoincrement/sequence keys and sequence tables

这实际上取决于数据库很好地支持什么.一些数据库支持比简单的"自动递增"更灵活的序列.这可能是可取的,也可能不是所需的(或者甚至可能是完成这类任务的唯一方法).序列表通常更灵活,但如果需要这种"灵活性",我会忍不住回go 参观设计模式,特别是当它涉及到触发器的使用时.虽然我不喜欢"限制ORM",但这在 Select "更简单"的自动增量或序列类型/数据库支持方面也可能有所不同.

无论使用哪种方法,在使用surrogate primary keys时,true primary key仍然应该被识别并编码到架构中.

此外,我认为"通过expose 自动序列PK而造成的安全危害"是错误地expose internal数据库属性的结果.虽然这是处理CRUD操作的一种非常简单的方式,但我相信internal keysexposed keys是有区别的(例如,相当多的客户数量).

这只是我的两点看法.

Edit,对Tim的其他回复:

我认为生成的PK与真实的PK问题是一个非常好的问题,也是我需要考虑的问题.我希望UUID一般能反映您提出的观点.我的犹豫不决是大小与整数/长.我没有意识到潜在的索引go 优化,这对我来说是一个更大的担忧.

我不会真的担心大小--如果UUID是最好的,那么它就是最好的.如果不是,那就不是.在overall scheme中,INT上额外的12个字节可能不会有太大的不同.SQL Server 2005+支持newsequentialid UUID生成功能,以避免与正常UUID生成相关的碎片.这一页对此进行了一些讨论.我相信其他数据库也有类似的解决方案.

您所说的"编码到模式中"不仅仅是指添加唯一性约束吗?

是.主键不必是唯一的[唯一]约束.仅仅使用代理PK并不意味着数据库模型应该受到影响:-)还可以使用额外的索引来覆盖,等等.

通过"区分",你是说代理主键永远不会泄漏吗?

我第一篇帖子的措辞有点难.与其说是"从不",不如说是"如果他们做到and it matters,那就是另一个问题".通常情况下,人们会通过可猜测的数字抱怨不安全——例如,如果您的订单是23,那么可能会有订单22和24,等等.如果这是您的"保护"和/或可能泄露敏感信息,那么系统已经存在缺陷.(分离内部和外部ID并不能从本质上解决这个问题,仍然需要身份验证/授权.然而,这是一个反对使用"顺序ID"的问题——我发现将nonce编码为分布式URL可以很好地处理这个for my用例.)

更多关于我的really wanted to get across:仅仅因为代理PK id恰好是8942并不意味着它是8942订单.也就是说,按照"某些字段仅在db内部"的设计,订单"编号"表面上可能完全不相关(但在db模型中完全受支持),例如"#2010-42c"或任何对业务需求有意义的内容.在大多数情况下,应该expose 的是这external个数字.

我觉得有时生成的键确实是真正的主键,因为其他字段是可变的(例如,用户可以更改邮箱和用户名).

这可能是within个数据库的情况,我不会对这一说法进行争辩.但是,再次保持代理主键是internal到数据库的情况下,只需确保只导出/导入可以很好识别的元组即可.如果用户名/邮箱可能会更改,那么这很可能包括在创建帐户时分配的UUID--并且很可能是代理PK本身.

当然,就像所有事情一样,保持开放状态,使模型适合问题,而不是模型的问题:-)例如,对于像Twitter这样的服务,他们使用自己的数字生成模式.请参见Twitter's new ID generation.与[一些]UUID生成不同,Twitter的方法(假设所有服务器都已正确设置)guarantees认为,任何分布式机器/进程都不会生成重复的ID,只需要64位,并且保持粗略的排序(最高有效位是时间戳).(推特产生的记录数量可能与当地要求无关;-)

编码愉快.

Database相关问答推荐

如何高效地存储棋局?

Rust 全局存储数据库连接

网络分区恢复后副本的更新数据发生了什么

数据库是序列图中的控制器还是边界?

是否有一个简单的工具可以将 mysql 转换为 postgresql 语法?

SQL 查询至少其中一项

这到底是做什么的 Class.forName("com.mysql.jdbc.Driver").newInstance();

什么是hibernate annotated类中使用的 catalog?

docker-compose mysql init sql 未执行

何时将数据库称为嵌入式数据库?

如何获取 PostgreSQL 数据库的最后访问/修改日期?

我可以为 dapper-dot-net 映射指定数据库列名称吗?

将 Redis 数据同步到 MySQL 的最佳策略是什么?

JavaScript 布尔搜索查询生成器接口库?

获取错误函数 to_date(timestamp without time zone, unknown) 不存在

表模块与域模型

标准化人类皮肤 colored颜色 以进行用户交互

由多个用户编辑数据库记录

遍历数据库中的每条记录 - Ruby on Rails / ActiveRecord

Windows phone 7 的本地 Sql 数据库支持