房间手动分页

问题描述 投票:0回答:1

我想知道使用 Room 实现手动 SQLite 分页的不同方法。我绝对不愿意使用 Paging 库,因为它的实现太具体了。

目前我正在使用

LIMIT
方法,隐式
offset
为 0,因为我想使用
Flow
接收迄今为止加载的所有页面的表更新。

SELECT * FROM TaskEntity ORDER BY createdAt DESC LIMIT :limit

但这有点违背了分页的目的,因为对于页面大小为

N
的页面
S
,我查询的不是
S
行,而是
S(N + 1)
行。我什至没有看到使用 search 方法的方法,因为我想监听更新。

我的问题是,如果可以实现复杂性仅取决于

S
的分页查询,并同时监听从0到
S(N + 1)
的行,我该怎么做,如果不能,我的规模是多少使用我当前的方法预计会出现性能问题吗?

android sqlite pagination android-room
1个回答
0
投票

也许以下可以作为基础:-

/* STEP 3 - get rows (all for brevity and simplicity of the demo) with the page number for 10 pagesize */
WITH
    pagesize(ps) AS (SELECT 10 /* The size of a page which could be passed e.g. (SELECT :pageSize) */),
    cte_paged(x,page,createdAt,blah) AS (
        SELECT -1,0,-1,'' 
        UNION ALL 
            SELECT
                 x+1,
                (x+1) / (SELECT ps FROM pagesize),
                (SELECT taskentity.createdAt FROM taskentity WHERE taskentity.createdAt > cte_paged.createdAt LIMIT 1),
                'xxx' /* Blah */ 
            FROM cte_paged LIMIT (SELECT count(*) FROM taskentity)
    )
SELECT *,datetime(createdat,'unixepoch') /* column added just to make demo easier */ AS easyread FROM cte_paged WHERE x > -1;
  • WHERE pagesize 是页面的大小。

从下面解释的演示中,页面大小为 10 时,这可能是输出(如果最终的 WHERE 子句进行相应修改,则很容易成为单个页面)。

  • 可以看到每页10行

这是如何运作的

它使用 CTE(通用表表达式(类似于临时表,但它们仅在执行期间存在))。

pagesize cte 将是单行单列ps,只是为了能够传递和使用页面大小。

cte_paged 是一个递归 cte。它有 4 列:-

  • x 每行加 1 的计数器(不是真正必需的,但可能更容易理解)

  • 页面类似,但除以页面,以便特定行所在的页面。

  • createdAt 将成为该行的任务实体的createdAt

  • blah 将根据任务实体的 blah 列(blah 代表其他列)

  • 递归是由于 UNION ALL 本身有效,如果没有结束方式,它将永远不会结束,因此 LIMIT (未满足的 WHERE 子句也满足循环的结束)

SELECT 是用 WITH 来完成的。

  • 参见示例

演示

下面分 3 个步骤/阶段演示了上述内容(如果考虑清理,则为 4 个步骤/阶段)。 第一阶段加载一些数据,1000行,createdAt列是当前日期时间,然后每个后续行的时间少于1小时。请注意,这还使用了递归 CTE WITHINSERTing 数据。其他每个stage根据传递的页面大小提取数据(硬编码为 SQLite 工具已用于演示)。

阶段/步骤1设置一些测试数据

DROP TABLE IF EXISTS taskentity; /* just in case */
/* Stage 1 Create the core data to be tested */
CREATE TABLE IF NOT EXISTS taskentity (createdat INTEGER PRIMARY KEY, blah TEXT);
/* Use a recursive CTE to load some data (1000 rows) with createdAt being the current datetime less 1 hour*/
WITH
    cte(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cte LIMIT 1000)
INSERT INTO taskentity SELECT strftime('%s','now','-'||(x+1)||' hours'),'blah'||(x+1) FROM cte;
SELECT * FROM taskentity; /* output the core data that has been created */

*结果:-

  • 请注意,blah1001 实际上是插入的最后一行,但作为唯一可用索引显示的第一行位于 createAt 列上,默认排序为 ASC 结尾。因此最早的createdAt(现在小于1000小时)首先出现。
    • 在现实生活中,如果顺序很重要,那么应该使用 ORDER BY,你永远不应该尝试依赖你认为查询优化器会做什么。

阶段/步骤 2第一个示例

/* STEP 2 - get rows (all for brevity and simplicity of the demo) with the page number for 256 pagesize */
WITH
    pagesize(ps) AS (SELECT 256),
    cte_paged(x,page,createdAt,blah) AS (
        SELECT -1,0,-1,'' 
        UNION ALL 
            SELECT
                 x+1,
                (x+1) / (SELECT ps FROM pagesize),
                (SELECT taskentity.createdAt FROM taskentity WHERE taskentity.createdAt > cte_paged.createdAt LIMIT 1),
                (SELECT taskentity.blah FROM taskentity WHERE taskentity.createdAt > cte_paged.createdAt LIMIT 1)
            FROM cte_paged LIMIT (SELECT count(*) FROM taskentity)
    )
SELECT *,datetime(createdat,'unixepoch') AS easyread FROM cte_paged WHERE createdAt >= 0;

在此示例中,每页的行数为 256(请参阅页面大小 CTE)。结果包括:-

  • x 列实际上是行号
  • page 是前 256 行 (0-255)、1 257-511 等行所属第 0 页的页。

阶段/步骤 3 每页 10 个(如最初显示的代码和结果)

阶段/步骤 4 清理 /* 清理演示环境 */ DROP TABLE IF EXISTS 任务实体;

适合在房间内使用。基本上整个 SQL 都编码在

@Query
参数中。请参阅初始代码中的注释,例如将页面大小作为参数传递的示例。

  • 显然,cte 的名称可以更改以适应需要。
  • 演示代码可能不是最有效的,编写它的目的是希望相对容易地了解正在发生的事情。
© www.soinside.com 2019 - 2024. All rights reserved.