我有一个People
表(Id, first_name, last_name)
,主键是id
。我希望能够查找(last_name, first_name, Id)
订购的表格中的前N个人。在某些情况下,我需要查找下一个N人,依此类推。我想有效地做到这一点。这样做的最佳方式是什么?
答案 0 :(得分:4)
主要有两种方式:
LIMIT
和OFFSET
LIMIT
和上一页的键OFFSET策略允许您读取任意页面,但效率不高,因为每次查询运行时都必须读取所有先前页面中的行。它是最容易实现的,并且可以是一种可接受的策略(特别是如果您只需要前几页),但通常不建议这样做。前一页键策略确实要求按顺序读取页面,但效率更高,因为每个页面只读取所需的行。
因此,让我们从原始查询开始,从(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
您可能希望确保查询都能查看数据库数据的一致快照,因此您需要确保查询序列始终从同一时间戳读取。完成此操作的最简单方法是将第一个查询设置为Read 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在这种情况下也很有用,因为它可以更容易地对表格上的范围扫描进行分页。