我如何实施分页?

时间:2017-02-16 00:22:42

标签: google-cloud-platform google-cloud-spanner

我有一个People(Id, first_name, last_name),主键是id。我希望能够查找(last_name, first_name, Id)订购的表格中的前N个人。在某些情况下,我需要查找下一个N人,依此类推。我想有效地做到这一点。这样做的最佳方式是什么?

1 个答案:

答案 0 :(得分:4)

主要有两种方式:

  • 使用LIMITOFFSET
  • 使用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在这种情况下也很有用,因为它可以更容易地对表格上的范围扫描进行分页。