【问题标题】:Optimize Groovy code优化 Groovy 代码
【发布时间】:2015-04-07 20:37:55
【问题描述】:

我对 Groovy/Grails 领域还很陌生。我最近修改了一些代码以添加以下块。

result.processed.each{
    def queueEntry = QueueEntry.findById(it.id)<<<START ADD>>>
    Set dates = new HashSet<Long>()

    def children = QueueEntry.findAllByParent(queueEntry)

    for(QueueEntry qe : children){
        def f = new GregorianCalendar()
        f.setTimeInMillis(DateUtils.getClearedTime(qe.entryTimestamp))
        def l = new GregorianCalendar()
        l.setTimeInMillis(DateUtils.getClearedTime(qe.exitTimestamp))
        while(f < l){
            if(f.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY && f.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY){//only add weekdays
                dates.add(f.time.time)
            }
            def xx = new GregorianCalendar()
            xx.setTimeInMillis(f.time.next().time)
            f = xx
        }
        dates.add(l.time.time)
    } <<<STOP ADD>>>
    Set outsideDays = it.numberOfDaysOutsideCVB
    Set days = DateUtils.businessDaysBetweenDates(it.entryTimestamp, it.exitTimestamp)
    days.removeAll(outsideDays)
    days.removeAll(dates)
    turnTimes << days.size()
}

应用程序现在正在爬行。我显然做错了什么。当它针对小型数据集运行时,它将缓慢完成。在较大的集合上,它不会完成。在此更改之前,它已完成。

【问题讨论】:

  • 通常,由于休眠映射做了一些意想不到的事情,数据库访问可能会成为问题。打开休眠日志记录(调试“org.hibernate.SQL”),看看它在做什么。
  • 看一下while循环里面的代码。它嵌套在 for 循环中,因此您在此块中存在潜在的瓶颈。你在这里尝试过什么吗?也许构造一个 GregorianCalender 对象的成本太高而不能做这么多次?
  • 你确定你的while循环退出了吗?此外,您现在有 3 个嵌套循环(每个、for、while)
  • @zcleghern 我确实尝试更改代码以不每次都构造 GregorianCalender 对象,并且速度稍快。感谢您的建议。

标签: groovy


【解决方案1】:

您可以从以下更改的行开始。

// Proposed

import static java.util.Calendar.*

// Query for all the children upfront instead of hitting
// database twice on each iteration. 
// You can also avoid N + 1 situation if children is fetched eagerly
def allChildren = QueueEntry.where {
    id in (result.processed*.id as List<Long>)
}.children.list() 

def turnTimes = result.processed.collect { entry ->
    allChildren.findAll { it.parent.id == entry.id }.collect { child ->
        Set dates = []
        new Date( child.entryTimeStamp ).upto( new Date( child.exitTimestamp ) ) {
            if ( !( it[DAY_OF_WEEK] in [ SUNDAY, SATURDAY ] ) ) {
                dates << it.time
            }
        }
        Set outsideDays = child.numberOfDaysOutsideCVB
        Set days = 
            DateUtils.businessDaysBetweenDates(
                child.entryTimestamp, 
                child.exitTimestamp 
            )

        ( days - outsideDays - dates )?.size() ?: 0
    }
}

假设:

  • QueueEntryhasMany children
  • entryTimestamp/exitTimestampjava.sql.Timestamp
  • entryTimestamp/exitTimestamp 不为空,entryTimestampexitTimestamp 之前。

正如 Burt 建议的那样,这个问题最适合 codereview.stackexchange.com

【讨论】:

  • QueueEntry 未设置为 hasMany 子项。如果不是这样设置有没有办法做到这一点?
  • 是的。 QueueEntry.where { parent.id in (result.processed*.id as List&lt;Long&gt;) }.list() 应该这样做。
猜你喜欢
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
  • 2014-12-26
  • 2011-12-21
相关资源
最近更新 更多