我想知道使用 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)
的行,我该怎么做,如果不能,我的规模是多少使用我当前的方法预计会出现性能问题吗?
也许以下可以作为基础:-
/* 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;
从下面解释的演示中,页面大小为 10 时,这可能是输出(如果最终的 WHERE 子句进行相应修改,则很容易成为单个页面)。
这是如何运作的
它使用 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 WITH 它INSERTing 数据。其他每个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 */
*结果:-
阶段/步骤 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)。结果包括:-
阶段/步骤 3 每页 10 个(如最初显示的代码和结果)
阶段/步骤 4 清理 /* 清理演示环境 */ DROP TABLE IF EXISTS 任务实体;
适合在房间内使用。基本上整个 SQL 都编码在
@Query
参数中。请参阅初始代码中的注释,例如将页面大小作为参数传递的示例。