从 Id 中删除 @GeneratedValue 对性能有什么影响
What's the effect of removing @GeneratedValue from the Id on the performance
我正在开发一个 RCP 应用程序,它使用 Rest 与 Tomcat- 服务器通信。由于我们获得了越来越多的数据,load/copy-routines 正缓慢但坚定地变得过时。有时我需要几分钟来执行一些复制操作。所以我正在寻找一些建议,如何加快我的例程。
以下是我使用的技术:
- RCP 客户端(e4 平台)
- Tomcat8 台服务器
- Oracle-DB
- JDBC 作为 API 和 Hibernate
- 休息
第一件事。我检查了实体,几乎所有实体看起来都像下面的代码
@Entity
@SequenceGenerator(name = "CHECKITEM_SEQ", sequenceName = "CHECKITEM_SEQ", allocationSize = 1)
public class CheckItem extends AbstractTreeNode implements Serializable,Cloneable {...}
我想通过复制数据(大多数时候每次操作超过 200K)因为我将它们用作主键,
@Id
@GeneratedValue(generator = "CHECKITEM_SEQ", strategy = GenerationType.SEQUENCE)
public Integer getId() {
return id;
}
DB 必须为每个对象生成一个序列并检查其上的约束,所以我想知道如果我删除序列我会获得多少性能,因为我并不真正 use/need 它们在D B。现在我的问题:
- 有什么反对删除数据库中的约束(在这种特殊情况下是主键)吗?
- 有没有人more/better建议如何为此类操作提高数据库的性能?
- 我可以有教程或文档来帮助我完成这个过程吗?
我希望,我已经足够清楚了,我将不胜感激任何帮助。已经谢谢了。
使用 @GeneratedValue
标识符的问题在于,为了让 Hibernate 将新实体放入持久性上下文(一级缓存)中,它必须知道标识符。因此,当您使用基于 IDENTITY
或 SEQUENCE
的标识符时,这可能会影响 JDBC 驱动程序能够充分批量插入操作。
例如,您说明大多数实体使用以下序列生成:
@SequenceGenerator(
name = "CHECKITEM_SEQ",
sequenceName = "CHECKITEM_SEQ",
allocationSize = 1)
因此,每当对实体进行持久化操作时,您就是在告诉序列生成器只生成一个值,因此 JDBC 通信如下所示:
1. Get Next Sequence
2. Insert
3. Get Next Sequence
4. Insert
5. Get Next Sequence
6. Insert
如此处所示,我们无法批处理插入操作,因为我们必须在插入操作发生之前获取每个插入操作的标识符。最小化这种影响并处理批量插入的一种解决方案是使用更大的 allocationSize
.
1. allocationSize=10 -> Get Next 10 sequences
2 - 11. Perform 10 inserts in batch
Repeat
正如您在此处看到的那样,驱动程序可以批量执行 10 次插入,Hibernate 以 10 次为单位批量分配序列,因此插入速度更快。
显然这有一个小缺点,如果你分配了 10 个序列,但剩下的批次只需要插入 6 个实体;您已经浪费了 4 个序列值,但是您可以通过支持执行 jdbc 批量插入来获得性能。
下一个合乎逻辑的步骤是确定您是否可以完全消除对 @GeneratedValue
的使用,因为这将为您的复制操作提供批量插入的最佳性能;但是,您的数据模型可能无法做到这一点。在过去处理大量数据移动时,我尝试根据数据中的自然键定义主键,如果可能的话不涉及代理键。
欢迎阅读有关 JDBC 批处理操作的更多信息 here。
我正在开发一个 RCP 应用程序,它使用 Rest 与 Tomcat- 服务器通信。由于我们获得了越来越多的数据,load/copy-routines 正缓慢但坚定地变得过时。有时我需要几分钟来执行一些复制操作。所以我正在寻找一些建议,如何加快我的例程。
以下是我使用的技术:
- RCP 客户端(e4 平台)
- Tomcat8 台服务器
- Oracle-DB
- JDBC 作为 API 和 Hibernate
- 休息
第一件事。我检查了实体,几乎所有实体看起来都像下面的代码
@Entity
@SequenceGenerator(name = "CHECKITEM_SEQ", sequenceName = "CHECKITEM_SEQ", allocationSize = 1)
public class CheckItem extends AbstractTreeNode implements Serializable,Cloneable {...}
我想通过复制数据(大多数时候每次操作超过 200K)因为我将它们用作主键,
@Id
@GeneratedValue(generator = "CHECKITEM_SEQ", strategy = GenerationType.SEQUENCE)
public Integer getId() {
return id;
}
DB 必须为每个对象生成一个序列并检查其上的约束,所以我想知道如果我删除序列我会获得多少性能,因为我并不真正 use/need 它们在D B。现在我的问题:
- 有什么反对删除数据库中的约束(在这种特殊情况下是主键)吗?
- 有没有人more/better建议如何为此类操作提高数据库的性能?
- 我可以有教程或文档来帮助我完成这个过程吗?
我希望,我已经足够清楚了,我将不胜感激任何帮助。已经谢谢了。
使用 @GeneratedValue
标识符的问题在于,为了让 Hibernate 将新实体放入持久性上下文(一级缓存)中,它必须知道标识符。因此,当您使用基于 IDENTITY
或 SEQUENCE
的标识符时,这可能会影响 JDBC 驱动程序能够充分批量插入操作。
例如,您说明大多数实体使用以下序列生成:
@SequenceGenerator(
name = "CHECKITEM_SEQ",
sequenceName = "CHECKITEM_SEQ",
allocationSize = 1)
因此,每当对实体进行持久化操作时,您就是在告诉序列生成器只生成一个值,因此 JDBC 通信如下所示:
1. Get Next Sequence
2. Insert
3. Get Next Sequence
4. Insert
5. Get Next Sequence
6. Insert
如此处所示,我们无法批处理插入操作,因为我们必须在插入操作发生之前获取每个插入操作的标识符。最小化这种影响并处理批量插入的一种解决方案是使用更大的 allocationSize
.
1. allocationSize=10 -> Get Next 10 sequences
2 - 11. Perform 10 inserts in batch
Repeat
正如您在此处看到的那样,驱动程序可以批量执行 10 次插入,Hibernate 以 10 次为单位批量分配序列,因此插入速度更快。
显然这有一个小缺点,如果你分配了 10 个序列,但剩下的批次只需要插入 6 个实体;您已经浪费了 4 个序列值,但是您可以通过支持执行 jdbc 批量插入来获得性能。
下一个合乎逻辑的步骤是确定您是否可以完全消除对 @GeneratedValue
的使用,因为这将为您的复制操作提供批量插入的最佳性能;但是,您的数据模型可能无法做到这一点。在过去处理大量数据移动时,我尝试根据数据中的自然键定义主键,如果可能的话不涉及代理键。
欢迎阅读有关 JDBC 批处理操作的更多信息 here。