NHibernate和字符串主键

时间:2009-02-26 01:50:53

标签: nhibernate string orm primary-key

我们有一个使用字符串作为主键的旧数据库。我想在遗留数据库之上实现对象,以更好地实现某些业务逻辑并为用户提供更多功能。

我已经阅读过在桌面上使用字符串作为主键的地方很糟糕。我想知道为什么会这样?是因为区分大小写的问题吗?字符集?

...为什么这对NHibernate特别不好?

...并跟进...如果字符串确实产生了错误的主键,用int或GUID等替换数据库中的主键是否值得? (我们只涉及约25-30张表)

3 个答案:

答案 0 :(得分:5)

好的,我会抓住这个。我将给出一些快速的注意事项 - 我不是数据库方面的专家,我的经验是使用Hibernate(Java)而不是NHibernate,但是这里有。

我认为主键作为字符串的问题与用于在数据库中表示它们的SQL数据类型有关。由于在插入,查询等时始终使用主键,因此数据库引擎必须花费大量时间来比较主键。如果你使用数字,这些只是存储为字节,计算机真的很擅长快速做事。一旦开始使用字符串,这些操作(主要是比较)的成本就会显着上升。即使数据库引擎使用非常简洁的策略来比较密钥,将字节比较为字节而不是字符串仍然会更快。

在现代硬件上,这已经变得比以前少得多,而且索引问题几乎消失了。

我不确定为什么这在Hibernate(和NHibernate)中真的很糟糕,但根据我的经验,因为我的应用程序有一个复杂的对象图,它经常引用其他持久化对象,通常作为列表或集合,引用都是使用另一个对象的ID存储的,并且由于我已经实现了级联保存,提取等规则,这意味着主键一直在使用。 Hibernate - 我非常喜欢 - 倾向于完全按照它所说的去做,有时人们(特别是我!)告诉它做一些非常愚蠢的事情。因此,即使看似简单的更新或查询最终也会产生相当复杂的SQL。

所以 - 总而言之 - 作为主键的字符串很糟糕,因为对它们进行简单操作的成本,并且使用Hibernate可能会放大这一点。但在实践中,现代数据库引擎有很多简洁的策略来确保性能不会太差。 (Postgres - 可能是其他人 - 默认情况下为主键创建索引)

为了您的跟进 - 您应该更换钥匙吗?那么,这取决于您的应用程序的性能。如果性能至关重要,那么对于大批量和非常密集的应用来说,这可能是一个好主意,否则可能会带来最小的好处,而不得不花时间改变所有表格。您可以期望获得更好的结果来改进您使用NHibernate的策略(即获取策略以及何时进行级联保存等)。

答案 1 :(得分:1)

Andy K似乎暗示字符串不会存储为字节。那会很有趣!实际上,这完全取决于字符串PK的长度以及您使用的排序规则。它可能比bigint或int identity更快,几乎肯定会比Guids更快。如果这些字符串是你必须要搜索的东西,那么无论如何你都需要一个索引(甚至可能是聚集索引),所以为什么不把它们变成PK呢?

答案 2 :(得分:0)

使用字符串或字符会为系统添加大量accidental complexity。请考虑以下问题:

  • 如何处理区分大小写;
  • 如何处理填充。 NHibernate允许您插入一个较短的字符串,数据库将以静默方式向其添加填充,但它不会反映在您的持久化实体中。尝试使用内存ID再次获取实体将返回null;
  • 如何处理编码问题。 C#使用unicode字符串,数据库不迁移。你能说出如何处理转换吗?我不这么认为。
  • 大多数数据库都可以自动生成合成整数键,而无需额外的工作。使用字符串,您最有可能“手动”创建它们。除非你将它们隐藏在工厂后面(在DDD意义上),否则生成的代码会使你的域模型变得混乱。

虽然 andy K 提到的性能开销可能因索引而减少,但仍然很多次在内存中进行ID比较(哈希映射?)并且数据库优化不适用于那里。< / p>

我一直在研究一个带有字符串主键且没有外键的旧数据库的项目。我们不允许使用旧模式,因为遗留应用程序依赖于它的每个次要方面。我觉得字符串主键比缺少的外键更容易损害一致性,因为NHibernate非常优雅地处理后者。