【问题标题】:Large batch insertions: how to get INSERT SQL code from Grails?大批量插入:如何从 Grails 获取 INSERT SQL 代码?
【发布时间】:2011-06-17 10:30:39
【问题描述】:

我在 Grails 上使用大批量插入时遇到了很多麻烦。我尝试了用户提出的所有最常见的解决方法(例如 WithTransaction 等),但插入仍然慢得离谱。

我有一个包含大约 500K 个对象的批次。在 Gorm 上,数据库中的对象创建/插入每次插入执行大约 200 毫秒,这显然是不可接受的。 如果我在转储文件中从应用程序生成相关的 SQL INSERT 语句,然后直接在 DBMS 上运行转储文件,每次插入我得到

FileBuffer sqlFile = ...
largeBatch.each{
    def obj = createMyObject( it )
    String sql = getSQL code for obj insert
    sqlFile.write( sql )
}
execute sqlFile directly on JDBC

如何从瞬态对象中获取插入 SQL 代码?

【问题讨论】:

    标签: sql grails batch-file grails-orm bulkinsert


    【解决方案1】:

    有两种方法可以更快地执行插入数据的批处理:

    1. hibernate 无状态会话 (http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html)
    2. native sql (http://groovy.codehaus.org/api/groovy/sql/Sql.html)(创建 x 个插入语句并在 x 个数据库事务中触发它们)例如您可以创建一个 sql 转储并在一个事务中触发此转储。

    使用休眠无状态会话,您还可以批量插入并可以插入域类实例,例如session.save(obj)。使用 navite sql 你必须自己构建语句。

    【讨论】:

    • 谢谢。是否可以提取 Hibernate 在 GORM 中生成的 SQL 代码?
    【解决方案2】:

    Ted Naleid 获得了good write-up 改进批量插入/更新性能。你遇到过吗?他的建议对我进行批量更新很有用。

    以下是文章下方的摘录:

    通常,grails 休眠会话 快速执行某事并且 返回。在导入过程中,我们做了很多 的处理,都一样 休眠会话。所有这些 通常是垃圾的对象 会话关闭时收集的 堆积起来。

    解决这个问题的最简单方法是 创建一个简单的方法来清除 定期收集这些集合。

    他建议定期刷新和清除会话。

    data.eachWithIndex { datum, index ->
        // insert or update datum
        if(index % 100 == 0) {
            def session = sessionFactory.currentSession()
            session.flush()
            session.clear()
            // also clear the Grails domain class property instance map
            // - it may be that this isn't necessary anymore; not sure, but the article is
            //   a bit old, so maybe it's been fixed within Grails.
        }
    }
    

    使用它,他将 10 万条记录的批量插入从大约 2.5 小时缩短到 3 分钟。

    @Ted - 如果你遇到这个问题/答案并想自己重复这个答案,我很乐意删除我的答案并为你的答案投票;你做了所有艰苦的工作来解决这个问题。谢谢!

    【讨论】:

    • 我尝试了那个解决方案,但我也有内存泄漏。我在这个阶段厌倦了 GORM,所以我想在这种情况下我会生成 SQL 并在 dbms 上脱机运行它。我只是想知道是否有一个聪明的发现可以从休眠中生成 SQL。
    【解决方案3】:

    您可以使用自定义 Hibernate Configuration 子类来捕获启动时生成的 SQL。我不确定以后访问它的最佳方式是什么 - 可能是类中的公共静态字段。

    代码如下(放在src/java下):

    package com.yourcompany.yourapp;
    
    import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration;
    import org.hibernate.HibernateException;
    
    public class DdlCapturingConfiguration extends GrailsAnnotationConfiguration {
    
       @Override
       public String[] generateSchemaCreationScript(Dialect d) throws HibernateException {
          String[] sql = super.generateSchemaCreationScript(d);
          // do something with the sql
          return sql;
       }
    }
    

    你可以像这样在grails-app/conf/DataSource.groovy注册它:

    dataSource {
       pooled = true
       driverClassName = ...
       username = ...
       password = ...
       dialect = ...
       configClass = com.yourcompany.yourapp.DdlCapturingConfiguration
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-04
      • 2014-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-20
      • 1970-01-01
      相关资源
      最近更新 更多