【问题标题】:Database Iterators in Conjunction with Paging与分页结合使用的数据库迭代器
【发布时间】:2013-10-24 22:26:42
【问题描述】:

我的问题是概念性的,但对我来说非常重要:

使用数据库时,您通常会从包含结果集的查询中返回一个迭代器。但是:当您想要进行分页时,您希望能够来回移动该结果集。然而,这是不可能使用迭代器的。所以这里的幼稚想法是使用转换来列出。但这又需要 O(n) 的时间,这可能会导致严重的性能问题。

我确定必须有解决此问题的方法(使用 elasticsearch :D 除外)。 解决这个问题的最佳方法是什么?

致以最诚挚的问候,

斯蒂芬

【问题讨论】:

    标签: scala iterator


    【解决方案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)]),但在调用它之前,您可以“分页”您的结果(通过调用.takedrop 等,构建 uopn 原始查询),在此示例中,SQL 为您执行分页 SLICK 会生成该 SQL,因此您只需执行 .take.drop 或其他操作。

    如果您的模型层利用 SLICK 的可组合性会有所帮助:您定义 SLICK 中的基本查询,而不是编写原始 SQL,这些查询可用作其他查询的构建块。

    【讨论】:

    • Slick 并不总是生成最佳查询,尤其是对于多个表。
    • 限制和偏移不一定表现良好,尤其是如果光标非常大。据我了解,所以 drop and take 只会转化为我假设的内容? .list 方法也正是我想要阻止的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多