Grails withCriteria fetch,或一种按预定顺序排序的快速方法

Grails withCriteria fetch, or a fast way to sort in predetermined order

数据库函数 returns 特定半径内所有事件的 ID,按距离排序。

之后,为了保持性能,我急切地在 withCriteria 中加载必要的集合,如下所示:

    def events = Event.withCriteria {
        'in'('id', ids)
        fetchMode("someRelation", FetchMode.JOIN)
        // a few more joins
        setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
    }

然而,这弄乱了顺序。我注意到此条件查询的结果 returns 所有按 id 排序的事件。这确实有点道理,因为 in 不保证任何类型的特殊排序(它应该也没有任何意义)。但是,这会带来一些问题,因为我希望对这个列表进行排序。

所以我所做的是:

    List<Event> temp = [];
    ids.each { id -> temp << events.find { it.id == id } }
    events = temp;

然而,当列表包含约 2400 个元素时,这段代码会增加大约 1 秒的总执行时间,这是我希望尽可能降低的时间。

有没有其他方法可以加快这个过程?

我认为至少有三种方法可以解决你的问题(我做了额外的研究和考虑):

SQL 方式

根据 this gist按字段排序 也可以用于 Postgres,不仅在 mysql 中,但它有点棘手,因为它不是直接支持。正如您在要点讨论中所读到的那样,有不同的方法,但我认为最后一种更清晰、更简单:添加自定义 order by 子句!

ORDER BY (ID=10, ID=2, ID=56, ID=40) DESC

要在 Grails 中创建 returns 具有特定类型对象的自定义 SQL 查询,您可以按照 this tutorial

Groovy方式(你现在的)

// only four id, for the sake of simplicity
def ids = [10, 2, 56, 40];

// get your events with your criteria
def events = Event.withCriteria {
    'in'('id', ids)
    fetchMode("someRelation", FetchMode.JOIN)
    // a few more joins
    setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
}

// create an array that maps event.id -> sortedEventIndex
def indexToIdArray = [];
// event with id 2 is at index 1
// event with id 10 is at index 0 
// ...
// [null, null, 1 , null, null, null, null, null, null, null, 0, ...]
ids.eachWithIndex{ num, idx -> indexToIdArray[$num] = $idx }

def sortedEvents = [];
events.each { ev -> sortedEvents[indexToIdArray[ev.id]] = ev }

通过这种方式,您在 O(n) 中进行了排序,消耗了一些额外的内存。 我不知道这个解决方案是否真的比你的更好,但你应该试一试。

另请参阅 this interesting article,了解如何查找 groovy 代码中的性能问题。

客户端方式

Return 将未排序的事件列表发送给带有排序数据的客户端,然后在客户端对它们进行排序。如果您的应用程序的客户端可以以更多方式对事件列表进行排序,我认为此解决方案可能会有用(每个排序操作仅在客户端完成)。

第 4 个,第 5 个,...

由于这也是一个性能问题,还有其他可能的解决方案(取决于您的 domain/environment):

  • 急切地缓存一切,甚至是有序的结果
  • 使用固定的点列表进行排序(如果我在p1附近,则使用p1进行排序)
  • 你的想法

希望对您有所帮助。