如何实现分页?
How do I implement pagination?
我有一个 People
table (Id, first_name, last_name)
,其中主键是 id
。我希望能够查找 (last_name, first_name, Id)
排序的 table 中的前 N 个人。在某些情况下,我需要查找下 N 个人,等等。我想有效地做到这一点。最好的方法是什么?
主要有两种方式:
- 使用
LIMIT
和OFFSET
- 使用
LIMIT
和key-of-previous-page
OFFSET 策略允许您读取任意页面,但效率不高,因为每次运行查询时,它都必须读取所有先前页面的行。它是最容易实现的并且可以是一个acceptable 策略(特别是如果你只想要前几页),但通常不推荐这样做。 key-of-previous-page 策略确实需要按顺序读取页面,但效率更高,因为每个页面只读取它需要的行。
所以让我们从原始查询开始,从按 (LastName, FirstName, Id)
:
排序的 table 中获取结果
SELECT
t.id,
t.first_name,
t.last_name
FROM
People as t
ORDER BY
t.last_name,
t.first_name,
t.id
LIMIT
@limit_rows
您可能希望确保所有查询都查看数据库数据的一致快照,因此您需要确保查询序列始终从相同的时间戳读取。完成此操作的最简单方法是将您的第一个查询设为 returnReadTimestamp
设置为 true 的 ReadOnly 事务。然后,您的后续查询也可以是 ReadOnly 事务,并且它们应该使用原始查询返回的相同时间戳作为它们的 readTimestamp。请注意,无论您选择哪种方法,ORDER BY
子句对于确保查询序列的结果一致至关重要。
假设返回的最后一行是 (1709, "John", "Smith")
。那么您第一次尝试获取下一页结果的查询可能如下所示:
SELECT
t.id,
t.first_name,
t.last_name
FROM
People as t
WHERE
t.last_name > "Smith"
OR
(t.last_name = "Smith" and t.first_name > "John")
OR
(t.last_name = "Smith" and t.first_name = "John" AND t.id > 1709)
ORDER BY
t.last_name,
t.first_name,
t.id
LIMIT
@limit_rows
中间的 WHERE
子句是新的。但是编写这个谓词比您想象的要棘手。您可能必须处理 NULL 值。您必须处理多个名为 John Smith 且具有不同 id
值的人的情况。你需要非常小心浮点数和 NaN
值。 Cloud Spanner 的 Read API 在这种情况下也很有用,因为它可以更轻松地在 table.
上对范围扫描进行分页
我有一个 People
table (Id, first_name, last_name)
,其中主键是 id
。我希望能够查找 (last_name, first_name, Id)
排序的 table 中的前 N 个人。在某些情况下,我需要查找下 N 个人,等等。我想有效地做到这一点。最好的方法是什么?
主要有两种方式:
- 使用
LIMIT
和OFFSET
- 使用
LIMIT
和key-of-previous-page
OFFSET 策略允许您读取任意页面,但效率不高,因为每次运行查询时,它都必须读取所有先前页面的行。它是最容易实现的并且可以是一个acceptable 策略(特别是如果你只想要前几页),但通常不推荐这样做。 key-of-previous-page 策略确实需要按顺序读取页面,但效率更高,因为每个页面只读取它需要的行。
所以让我们从原始查询开始,从按 (LastName, FirstName, Id)
:
SELECT
t.id,
t.first_name,
t.last_name
FROM
People as t
ORDER BY
t.last_name,
t.first_name,
t.id
LIMIT
@limit_rows
您可能希望确保所有查询都查看数据库数据的一致快照,因此您需要确保查询序列始终从相同的时间戳读取。完成此操作的最简单方法是将您的第一个查询设为 returnReadTimestamp
设置为 true 的 ReadOnly 事务。然后,您的后续查询也可以是 ReadOnly 事务,并且它们应该使用原始查询返回的相同时间戳作为它们的 readTimestamp。请注意,无论您选择哪种方法,ORDER BY
子句对于确保查询序列的结果一致至关重要。
假设返回的最后一行是 (1709, "John", "Smith")
。那么您第一次尝试获取下一页结果的查询可能如下所示:
SELECT
t.id,
t.first_name,
t.last_name
FROM
People as t
WHERE
t.last_name > "Smith"
OR
(t.last_name = "Smith" and t.first_name > "John")
OR
(t.last_name = "Smith" and t.first_name = "John" AND t.id > 1709)
ORDER BY
t.last_name,
t.first_name,
t.id
LIMIT
@limit_rows
中间的 WHERE
子句是新的。但是编写这个谓词比您想象的要棘手。您可能必须处理 NULL 值。您必须处理多个名为 John Smith 且具有不同 id
值的人的情况。你需要非常小心浮点数和 NaN
值。 Cloud Spanner 的 Read API 在这种情况下也很有用,因为它可以更轻松地在 table.