我们有一个使用字符串作为主键的遗留数据库。我想在遗留数据库之上实现对象,以更好地实现一些业务逻辑并为用户提供更多功能。
我在某些地方读过,在表上使用字符串作为主键是不好的。我想知道这是为什么?是因为区分大小写的问题吗?字符集?
... 为什么这对 NHibernate 来说特别糟糕?
...并跟进...如果字符串确实生成了错误的主键,是否值得用整数或 GUID 等替换数据库中的主键?(我们只涉及大约 25-30 张桌子)
我们有一个使用字符串作为主键的遗留数据库。我想在遗留数据库之上实现对象,以更好地实现一些业务逻辑并为用户提供更多功能。
我在某些地方读过,在表上使用字符串作为主键是不好的。我想知道这是为什么?是因为区分大小写的问题吗?字符集?
... 为什么这对 NHibernate 来说特别糟糕?
...并跟进...如果字符串确实生成了错误的主键,是否值得用整数或 GUID 等替换数据库中的主键?(我们只涉及大约 25-30 张桌子)
好的,我将对此进行尝试。我将给出几个快速警告 - 我不是数据库专家,我的经验是使用 Hibernate (Java) 而不是 NHibernate,但这里有。
我认为主键作为字符串的问题与用于在数据库中表示它们的 SQL 数据类型有关。由于在插入、查询等操作时始终使用主键,因此数据库引擎不得不花费大量时间来比较主键。如果您使用的是数字,它们只是存储为计算机非常擅长快速处理的字节。一旦你开始使用字符串,这些操作的成本(主要是比较)就会显着增加。即使数据库引擎使用非常简洁的策略来比较键,将字节作为字节而不是字符串进行比较仍然总是更快。
然而,在现代硬件上,这个问题已经比过去少了很多,而且有了索引,这个问题几乎消失了。
我不确定为什么这在 Hibernate(和 NHibernate)中真的很糟糕,但根据我的经验,因为我的应用程序有一个复杂的对象图,这些对象经常引用其他持久对象,通常作为列表或集合,引用都是使用另一个对象的 ID 存储的,并且由于我为级联保存、获取等制定的规则,这意味着主键一直在使用。Hibernate——我非常喜欢——倾向于完全按照它的指示去做,有时人们(尤其是我!)会告诉它做一些非常愚蠢的事情。结果,即使是看似简单的更新或查询最终也会生成相当复杂的 SQL。
所以 - 总而言之 - 字符串作为主键是不好的,因为对它们进行简单操作的成本和使用 Hibernate 可能会放大这一点。但在实践中,现代数据库引擎有很多巧妙的策略来确保性能影响不是那么糟糕。(Postgres - 可能还有其他 - 默认情况下为主键创建索引)
为了您的跟进 - 您应该更换钥匙吗?好吧,这取决于您的应用程序的性能。如果性能很关键,那么对于大容量和非常密集的应用程序来说,这可能是一个好主意,否则可能会带来最小的好处,缺点是不得不花时间更改所有表。您可以期望得到更好的结果,改进您与 NHibernate 一起使用的策略(即获取策略以及何时进行级联保存等)。
Andy K 似乎暗示字符串不存储为字节。那会很有趣!实际上,这完全取决于字符串 PK 的长度以及您使用的排序规则。它甚至可能比 bigint 或 int identity 更快,并且几乎肯定会比 Guids 更快。如果这些字符串是您无论如何都必须搜索的东西,那么无论如何您都需要一个索引(甚至可能是聚集索引),所以为什么不将它们设为 PK!
使用字符串或字符会意外增加系统的大量复杂性。考虑以下问题:
尽管andy K提到的性能开销可以因为索引而减少,但您仍然多次在内存中进行 ID 比较(哈希映射?)并且 DB 优化不适用于那里。
我一直在研究一个带有字符串主键且根本没有外键的遗留数据库的项目。我们不允许修改旧模式,因为旧版应用程序依赖于它的每个小方面。我觉得字符串主键比缺少的外键更能损害一致性,因为 NHibernate 非常优雅地处理了后者。