【问题标题】:Bad performance with hibernate休眠性能不佳
【发布时间】:2019-03-28 22:00:13
【问题描述】:

我阅读了很多关于设置休眠以保存大量新实体的信息,但我错过了一些东西,因为插入性能真的很差......

这是我的配置

休眠配置:

@Configuration
@EnableTransactionManagement
@ComponentScans(value = { @ComponentScan("com.xxxxx)})
public class HibernateConfiguration
{


@Bean
public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSource());
    sessionFactory.setPackagesToScan(new String[] { "com.xxxx" });
    sessionFactory.setHibernateProperties(hibernateProperties());
    return sessionFactory;
 }

@Bean
public DataSource dataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setUrl(XXXX);
    dataSource.setUsername(XXXX);
    dataSource.setPassword(XXXX);
    dataSource.setTestOnBorrow(true);
    dataSource.setValidationQuery("SELECT 1");
    dataSource.setInitialSize(3);
    dataSource.setMaxActive(10);
    return dataSource;
}

private Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put(Environment.DIALECT, "org.hibernate.dialect.PostgreSQL95Dialect");
    properties.put(Environment.SHOW_SQL, false);
    properties.put(Environment.FORMAT_SQL, false);
    properties.put("hibernate.default-lazy", true);
    properties.put(Environment.USE_NEW_ID_GENERATOR_MAPPINGS, true);
    properties.put(Environment.HBM2DDL_AUTO, "none");
    properties.put(Environment.STATEMENT_BATCH_SIZE, 50);
    properties.put(Environment.STATEMENT_FETCH_SIZE, 400);
    properties.put(Environment.ORDER_INSERTS, true);
    properties.put(Environment.ORDER_UPDATES, true);
    properties.put(Environment.BATCH_VERSIONED_DATA, true);
    properties.put(Environment.GENERATE_STATISTICS, true);
    properties.put(Environment.HQL_BULK_ID_STRATEGY, InlineIdsSubSelectValueListBulkIdStrategy.class);
   return properties;        
}

@Bean
public HibernateTransactionManager transactionManager()
{
   HibernateTransactionManager txManager = new HibernateTransactionManager();
   txManager.setSessionFactory(sessionFactory().getObject());
   return txManager;
}

@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation()
{
      return new PersistenceExceptionTranslationPostProcessor();
}

}

为了我的测试,我创建了一个没有任何关系的简单表

实体:

@Entity
@Table(name="performance_test")
@NamedQuery(name="PerformanceTest.findAll", query="SELECT t FROM PerformanceTest t")
public class PerformanceTest
{
@Id
@Id
@GenericGenerator(
        name = "PERFORMANCE_TEST_ID_GENERATOR",
        strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @Parameter(name = "sequence_name", value = "performance_test_id_seq"),
                @Parameter(name = "optimizer", value = "pooled-lo"),
                @Parameter(name = "increment_size", value = "1")
        }
)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PERFORMANCE_TEST_ID_GENERATOR")
private Long id;
private Long id;

@Column(name="first_name")
private String firstName;

@Column(name="last_name")
private String lastName;

@Column(name="salary")
private Integer salary;

public PerformanceTest(){};

public Long getId()
{
    return id;
}

public void setId(Long id)
{
    this.id = id;
}

public String getFirstName()
{
    return firstName;
}

public void setFirstName(String firstName)
{
    this.firstName = firstName;
}

public String getLastName()
{
    return lastName;
}

public void setLastName(String lastName)
{
    this.lastName = lastName;
}

public Integer getSalary()
{
    return salary;
}

public void setSalary(Integer salary)
{
    this.salary = salary;
}

}

DAO 实现(我使用了这两种方法,但没有显着改进

@Override
public void saveBulkElement (Set<T> listOfElement,Integer bulkSize)
{
    if(listOfElement == null || listOfElement.size() == 0)
        return;

    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    session.setJdbcBatchSize(batchSize);
    try
    {
        int flushIndex = 0;
        Iterator<T> ite = listOfElement.iterator();
        while (ite.hasNext())
        {
            T element = (T) ite.next();
            session.persist(element);
            flushIndex++;
            int size = bulkSize != null ? bulkSize:batchSize;
            if((flushIndex % size == 0 && flushIndex > 0) || !ite.hasNext())
            {
                session.flush();
                session.clear();
            }
        }

        tx.commit();
    }
    catch (HibernateException e)
    {
        if (tx != null)
            tx.rollback();
    }
    finally
    {
        session.close();
    }              
}

@Override
public void saveStatelessBulkElement (Set<T> listOfElement)
{
    if(listOfElement == null || listOfElement.size() == 0)
        return;

    StatelessSession session = sessionFactory.openStatelessSession();
    Transaction tx = session.beginTransaction();
    session.setJdbcBatchSize(listOfElement.size() < statelessBatchSize ? listOfElement.size():statelessBatchSize);
    try
    {
        Iterator<T> ite = listOfElement.iterator();
        while (ite.hasNext())
        {
            T element = (T) ite.next();
            session.insert(element);
        }

        tx.commit();
    }
    catch (HibernateException e)
    {
        if (tx != null)
            tx.rollback();
    }
    finally
    {
        session.close();
    }              
}

我的测试是非常简单地插入 100 个新元素 我设置休眠显示统计数据

这是我得到的:

[StatisticalLoggingSessionEventListener] - Session Metrics {
137291307 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
12909270 nanoseconds spent preparing 100 JDBC statements;
13660416454 nanoseconds spent executing 100 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
32506326 nanoseconds spent executing 2 flushes (flushing a total of 100 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
[StatisticalLoggingSessionEventListener] - Session Metrics {
141927634 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
0 nanoseconds spent preparing 0 JDBC statements;
0 nanoseconds spent executing 0 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}

只有 100 件商品需要 14 秒!!!

我错过了 hibernate 的配置吗?

我用一个好的生成器更新了我的实体,问题仍然存在

================================================ ====

第一次更新:

我检查了 DB seq 生成器

Sequence "recntrek.performance_test_id_seq"
Column     |  Type   |          Value          
---------------+---------+-------------------------
sequence_name | name    | performance_test_id_seq
last_value    | bigint  | 293551
start_value   | bigint  | 1
increment_by  | bigint  | 1
max_value     | bigint  | 9223372036854775807
min_value     | bigint  | 1
cache_value   | bigint  | 1
log_cnt       | bigint  | 32
is_cycled     | boolean | f
is_called     | boolean | t

我将 increment_by AND cache_value 改为 50...

我重新运行我的测试,它花了 1.4 秒

我用 10000 个新元素进行了另一次测试,花了大约 30 秒

这是一个很大的进步,但从 Vlad Mihalcea 的 page 来看,我离取得好成绩还有很长的路要走

【问题讨论】:

  • 我有其他表具有良好的生成器定义,我也有同样的问题..
  • 如果 id 的默认值取自同一 performance_test_id_seq,由 serialbigserial 类型定义,您可以使用 @GeneratedValue(strategy=GenerationType.IDENTITY) 并节省一半的查询,但是我认为改进会很小。值得一试。

标签: java performance hibernate


【解决方案1】:

似乎性能不佳与数据库序列的定义有关

这里有一些不同序列配置的结果:

  • 100 行:increment_by 和 cache_value 设置为 1 大约需要 14 秒
  • 100 行:increment_by 和 cache_value 设置为 50,耗时约 1.4 秒
  • 10K 行:increment_by 和 cache_value 设置为 50,大约需要 30 秒
  • 10K 行:increment_by 和 cache_value 设置为 500,大约需要 5 秒
  • 10K 行:increment_by 和 cache_value 设置为 1000 大约需要 4 秒

每次更改这些值时,我也更改了生成器实体定义(increment_size 值)

@GenericGenerator(
    name = "PERFORMANCE_TEST_ID_GENERATOR",
    strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
    parameters = {
            @Parameter(name = "sequence_name", value = "performance_test_id_seq"),
            @Parameter(name = "optimizer", value = "pooled-lo"),
            @Parameter(name = "increment_size", value = "1")
    }
)

希望这会有所帮助...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 2016-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多