这篇文章说:
与 identity 不同,列值的下一个数字将从内存而不是磁盘中检索——这使得 Sequence 比 Identity 快得多
这是否意味着ID来自磁盘以防身份?如果是,那么哪个磁盘以及如何?
使用序列,我可以在日志中看到插入新记录时对 DB 的额外选择查询。但是在身份的情况下,我没有在日志中找到额外的选择查询。那么序列如何变得比身份更快?
这篇文章说:
与 identity 不同,列值的下一个数字将从内存而不是磁盘中检索——这使得 Sequence 比 Identity 快得多
这是否意味着ID来自磁盘以防身份?如果是,那么哪个磁盘以及如何?
使用序列,我可以在日志中看到插入新记录时对 DB 的额外选择查询。但是在身份的情况下,我没有在日志中找到额外的选择查询。那么序列如何变得比身份更快?
序列使用的策略:
在插入新行之前,向数据库询问下一个序列值,然后以返回的序列值作为 ID 插入这一行。
身份使用的策略:
在不指定 ID 值的情况下插入一行。插入行后,向数据库询问最后生成的 ID。
因此,在这两种情况下,查询的数量是相同的。但是,Hibernate 默认使用对序列生成器更有效的策略。事实上,当它请求下一个序列值时,它会在内存中保留 50 个(即默认值,IIRC,它是可配置的)下一个值,并将这 50 个下一个值用于接下来的 50 次插入。只有在 50 次插入后,它才会进入数据库以获取 50 个下一个值。这极大地减少了自动 ID 生成所需的 SQL 查询数量。
身份策略不允许这样的优化。
生成器IDENTITY
将始终需要数据库命中来获取主键值,而无需等待刷新以将当前实体状态转换与数据库同步。
因此IDENTITY
生成器不能很好地与 Hibernate 后写一级缓存策略配合使用,因此IDENTITY
生成器禁用了 JDBC 批处理。
序列生成器可以从数据库值预分配中受益,您甚至可以采用hi/lo
优化策略。
在我看来,最好的生成器是pooled
和pooled-lo
序列生成器。这些生成器将批处理友好的序列生成器与客户端值生成优化相结合,该优化与其他可能在不了解我们生成策略的情况下插入行的 DB 客户端兼容。
无论如何,您永远不应该选择TABLE
生成器,因为它的性能非常糟糕。
也许这会回答你的问题:
与插入行时生成的标识列值不同,应用程序可以在插入行之前通过调用 NEXT VALUE FOR 函数获取下一个序列号。在调用 NEXT VALUE FOR 时分配序列号,即使该编号从未插入到表中。NEXT VALUE FOR 函数可用作表定义中列的默认值。使用 sp_sequence_get_range 一次获取多个序列号的范围。
你可以在这里找到详细信息
Identity 不需要额外的选择查询,因为 Identity 依赖于表,而 Sequence 独立于表,但正因为如此,我们甚至可以在创建行之前获取序列(当你执行 session.save(T entity) 时,序列甚至在之前生成你提交交易)。
序列:您创建或更新实体->每次保存实体时->休眠获取下一个序列值->您的程序在所有进程完成后返回值,无异常或回滚->您提交所有事务->休眠插入所有完整实体
身份:提交事务时,插入不完整的实体(必须从身份列中获取)。所以序列的INSERT命令肯定更慢,但优点是如果取消插入,计数不会增加。
虽然我个人是 Hibernate 的新手,但据我回忆,使用 Identity 基本上意味着 Hibernate 将检查您的数据库中下一个可能的 id 值是什么,并为它保留一个值。
对于序列,您基本上告诉 Hibernate 根据您提供的特定序列生成下一个值。所以它必须通过查看下一个可能的 id 值来实际计算下一个 id。因此,触发了额外的查询。