我使用grails作为穷人的etl工具,用于将一些相对较小的db对象从1 db迁移到下一个db。我有一个控制器从一个db(mysql)读取数据并将其写入另一个(pgsql)。由于grails 2.1.X中多数据源支持的限制,它们使用类似的域对象,但不完全相同。
下面你会看到我的控制器和服务代码:
class GeoETLController {
def zipcodeService
def migrateZipCode() {
def zc = zipcodeService.readMysql();
zipcodeService.writePgSql(zc);
render{["success":true] as JSON}
}
}
服务:
class ZipcodeService {
def sessionFactory
def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
def readMysql() {
def zipcode_mysql = Zipcode.list();
println("read, " + zipcode_mysql.size());
return zipcode_mysql;
}
def writePgSql(zipcodes) {
List<PGZipcode> zips = new ArrayList<PGZipcode>();
println("attempting to save, " + zipcodes.size());
def cntr = 0;
zipcodes.each({ Zipcode zipcode ->
cntr++;
def props = zipcode.properties;
PGZipcode zipcode_pg = new PGZipcode(zipcode.properties);
if (!zipcode_pg.save(flush:false)) {
zipcode_pg.errors.each {
println it
}
}
zips.add(zipcode_pg)
if (zips.size() % 100 == 0) {
println("gorm begin" + new Date());
// clear session here.
this.cleanUpGorm();
println("gorm complete" + new Date());
}
});
//Save remaining
this.cleanUpGorm();
println("Final ." + new Date());
}
def cleanUpGorm() {
def session = sessionFactory.currentSession
session.flush()
session.clear()
propertyInstanceMap.get().clear()
}
}
大部分内容来自我自己的代码,然后进行调整以尝试获得与http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
中所见类似的效果因此,在查看我的代码时,每当调用zipcode_pg.save()时,都会创建一个insert语句并将其发送到数据库。适用于数据库一致性,不适合批量操作。
我的即时刷新的原因是什么(注意:我的数据源和congig groovy文件没有相关更改)?按照这个速度,处理每批100个(每秒14次插入)需要大约7秒钟,当你处理10,000行时,这只是很长一段时间......
感谢建议。
注意:我考虑使用纯ETL工具,但是已经构建了如此多的域和服务逻辑,使用grails计算将是对资源的良好重用。但是,没想到这种批量操作的质量
答案 0 :(得分:1)
如果没有看到您的域对象,这只是一种预感,但我可能会尝试在save()调用中指定validate:false。 Saveate()由save()调用,除非你告诉Grails不这样做。例如,如果您对PGZipcode域对象中的任何字段都有唯一约束,Hibernate必须在每个新记录上插入一个插件,以利用DBMS的独特功能并执行适当的验证。其他约束也可能需要DBMS查询,但现在只考虑唯一的跳转。
来自Grails Persistence: Transaction Write-Behind
Hibernate只在可能的情况下缓存数据库更新 当知道需要刷新时,或者当更改时,推动更改 flush以编程方式触发。 Hibernate的一个常见情况 将自缓存以来执行查询时刷新缓存更新 信息可能包含在查询结果中。但只要 你正在进行非冲突的保存,更新和删除 批处理直到会话被刷新。
或者,您可以尝试明确设置Hibernate会话的flush mode:
sessionFactory.currentSession.setFlushMode(FlushMode.MANUAL);
我认为默认的冲洗模式可能是AUTO。