我的问题具有概念性,但对我来说非常重要:
使用数据库时,通常会从包含结果集的查询中获取迭代器。但是:当您想要进行分页时,您希望能够来回移动该结果集。但是,使用迭代器是不可能的。所以这里的天真想法是使用转换列表。但这又需要一段时间O(n),这可能会导致严重的问题表现。
我确定必须有解决这个问题的方法(除了使用elasticsearch:D)。 解决这个问题的最佳方法是什么?
致以最诚挚的问候,
的Stefan
答案 0 :(得分:1)
您需要分页,但您不希望将未分页的结果集O(n)
加载到内存中。足够公平 - 从逻辑上讲,这意味着数据库必须提供分页的块。我认为大多数RDMS数据库都有类似'LIMIT'和'OFFSET'的SQL:
select id, name from foo where date > ? LIMIT $start, $page_size;
如果您正在处理MySQL,并且正在编写原始SQL,那么它就是这样的。但是对于像Slick这样的库,你可以拥有
val query = for {
d <- Parameter[Date]
f <- foo if f.date > d
} yield (f.id, f.name)
所以为了让所有行都不受欢迎,你可以
query(yesterday).list
// Select id, name from foo
如果你想要分页,那很简单:
query(yesterday).drop(20).take(5).list
// Select id, name from foo limit 20, 5 ; %% whatever; I suck at SQL and can't remember syntac
%% but you get the point.
这将返回5个元素的(Id, Name)
列表,假设您每页只需要5个元素。这意味着这个子序列将成为结果的第5页。
如果您在内存中query(yesterday)
结果不是List
,那么这就是您可能会做的事情:SLICK为您提供了Query
类型的查询抽象那
包含许多通常在集合中找到的有用方法。 .list
方法实际上是执行最终查询以获取List[T]
(在此示例中为List[(Int, String)]
),但在调用之前,您可以“搜索”结果(通过调用{{1 },.take
等,构建uopn原始查询)并在此示例中SQL为您执行分页
和SLICK生成该SQL,因此您只需执行drop
,.take
或其他任何操作。
如果你的模型层利用了SLICK的可组合性,那么它会有所帮助:你定义 SLICK中的基本查询而不是编写原始SQL,这些查询可用作其他查询的构建块。