Sql 带有HIBERNATE插入的JPA非常慢
我正在尝试使用JAP和HIBERNATE将一些数据插入SQLServer2008R2。除了速度非常慢之外,一切都“正常”。插入20000行大约需要45秒,而C#脚本只需要不到1秒 这个领域的任何老手都能提供一些帮助吗?我会非常感激的 更新:从下面的答案中得到了一些很好的建议,但仍然没有达到预期效果。速度是一样的 以下是更新后的persistence.xml:Sql 带有HIBERNATE插入的JPA非常慢,sql,sql-server,database,hibernate,jpa,Sql,Sql Server,Database,Hibernate,Jpa,我正在尝试使用JAP和HIBERNATE将一些数据插入SQLServer2008R2。除了速度非常慢之外,一切都“正常”。插入20000行大约需要45秒,而C#脚本只需要不到1秒 这个领域的任何老手都能提供一些帮助吗?我会非常感激的 更新:从下面的答案中得到了一些很好的建议,但仍然没有达到预期效果。速度是一样的 以下是更新后的persistence.xml: <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persi
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="ClusterPersist"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>cluster.data.persist.sqlserver.EventResult</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:sqlserver://MYSERVER:1433;databaseName=MYTABLE" />
<property name="javax.persistence.jdbc.user" value="USER" />
<property name="javax.persistence.jdbc.password" value="PASSWORD" />
<property name="javax.persistence.jdbc.driver"
value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="hibernate.show_sql" value="flase" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.connection.provider_class"
value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />
<property name="hibernate.c3p0.max_size" value="100" />
<property name="hibernate.c3p0.min_size" value="0" />
<property name="hibernate.c3p0.acquire_increment" value="1" />
<property name="hibernate.c3p0.idle_test_period" value="300" />
<property name="hibernate.c3p0.max_statements" value="0" />
<property name="hibernate.c3p0.timeout" value="100" />
<property name="hibernate.jdbc.batch_size" value="50" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
</properties>
</persistence-unit>
已更新,以下是MyRow的来源:
@Entity
@Table(name="MYTABLE")
public class MyRow {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Basic
@Column(name = "Num1")
private int Num1;
@Basic
@Column(name = "Num2")
private float Num2;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public float getNum1() {
return Num1;
}
public void setNum1(float num1) {
Num1 = num1;
}
public int getNum2() {
return Num2;
}
public void setNum2(int num2) {
Num2 = num2;
}
}
休眠“默认模式”很慢
它的优点是对象关系映射和一些缓存(但显然它对于批量插入不是很有用)
改为使用批处理来启用,您应该将hibernate.jdbc.batch_size属性初始化为介于10和50之间(仅限int)
如果仍然没有预期的那么快,那么我将回顾上面的文档,注意注释和第4.1节。特别是注意到,“如果使用标识标识符生成器,Hibernate将在JDBC级别透明地禁用插入批处理。”问题
如果您将Hibernate用作ORM,那么主要的性能问题之一就是它的“脏检查”的实现方式(因为如果没有字节码增强(这是所有基于JDO的ORM和其他一些ORM的标准配置),脏检查将永远是一种低效的攻击)
刷新时,需要对会话中的每个对象执行脏检查,以查看它是否“脏”,即它的一个属性自从数据库加载以来已更改。对于所有“脏”(已更改)对象,Hibernate必须生成SQL更新来更新表示脏对象的记录
众所周知,Hibernate脏检查在除少量对象之外的任何对象上都非常慢,因为它需要在内存中的对象之间执行“逐字段”比较,并在对象首次从数据库加载时获取快照。加载越多的对象(比如HTTP请求)以显示页面,则调用commit时需要的脏检查就越多
Hibernate脏检查机制的技术细节
您可以在此处阅读有关Hibernate的脏检查机制的更多信息,该机制是作为“逐字段”比较实现的:
在其他ORM中如何解决该问题
其他一些ORM使用的一种更有效的机制是使用自动生成的“脏标志”属性,而不是“逐字段”比较,但这通常仅在使用和促进字节码增强或字节码“编织”的ORM(通常是基于JDO的ORM)中可用,例如。,及其他
在字节码增强期间,DataNucleus或任何其他支持此功能的ORM将每个实体类增强为:
- 添加隐式脏标志属性
- 将代码添加到类中的每个setter方法,以便在调用时自动设置脏标志
- Hibernate传统上在人们评估ORM技术时,将其“不需要字节码增强”作为一项特性加以推广
- Hibernate的字节码增强实现存在历史可靠性问题,该实现可能不如从一开始就使用和促进字节码增强的ORM成熟
- 一些人仍然害怕使用字节码增强,这是因为他们提倡反“字节码增强”的立场,以及在ORMs的早期,某些团体向人们灌输了对字节码增强的恐惧
如今,字节码增强被用于许多不同的事情——不仅仅是持久性。它几乎已成为主流。这是一个古老的话题,但今天在寻找其他东西时遇到了这个问题。不幸的是,我没有很好地理解和记录这个常见的问题。很长一段时间以来,Hibernate的文档只有上面发布的简短注释。 从版本5开始,有一个更好但仍然很简单的解释: 超大集合插入速度慢的问题只是Id生成策略选择不当:
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
使用标识策略时,需要了解的是,数据库服务器在物理插入上创建行的标识。Hibernate需要知道分配的Id,以便在会话中使对象处于持久状态。数据库生成的Id仅在insert的响应中已知。Hibernate别无选择,只能执行20000个单独的插入来检索生成的ID。据我所知,它不适用于批处理,不适用于Sybase,也不适用于MSSQL。这就是为什么,无论您如何努力,并且正确配置了所有批处理属性,Hibernate都将执行单独的插入
唯一的解决办法是
hibernate.jdbc.batch_size=50
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@GenericGenerator(strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator")