我的问题是概念性的,但对我来说非常重要:
使用数据库时,您通常会从包含结果集的查询中获取迭代器。但是:当您想要进行分页时,您希望能够来回移动该结果集。然而,这是不可能使用迭代器的。所以这里的幼稚想法是使用转换来列出。但这又需要花费 O(n) 的时间,这可能会导致严重的性能问题。
我确定这个问题必须有解决方案(除了使用弹性搜索:D)。解决这个问题的最佳方法是什么?
最诚挚的问候,
斯特凡
您想要分页,但不想将未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.
(Id, Name)
假设您每页只需要 5 个元素,它将返回 5 个元素的列表。这意味着该子序列将是结果的第 5 页。
并不是说如果您在内存中query(yesterday)
没有 a List
of 结果,您可能会这样做:SLICK 为您提供了查询的抽象,一种Query
包含许多通常在集合中找到的有用方法的类型。该.list
方法实际上是执行最终查询以获取您的结果List[T]
(在此示例中List[(Int, String)]
),但在调用它之前,您可以“分页”您的结果(通过调用.take
等drop
来构建原始查询),在此示例中,SQL 执行为您分页,SLICK 会生成该 SQL,因此您只需执行.take
或.drop
其他任何操作。
如果您的模型层利用 SLICK 的可组合性会有所帮助:您在 SLICK 中定义基本查询而不是编写原始 SQL,并且这些查询可用作其他查询的构建块。