non-unique 列的偏移查询

Offset queries for non-unique columns

假设我有这样一个 table:

CREATE TABLE book (
 id INTEGER PRIMARY KEY,
 title VARCHAR(32) NOT NULL
);

并且我想支持带偏移量的查询,以支持 API 这将是 return 图书列表,按 non-unique[=45= 排序] 具有给定偏移量和限制的标题字段。

这里的问题是什么是最有效的方法 [1] 为 non-unique title 列定义唯一索引(或辅助列或类似的东西),可以用作我使用 ORDER BY title 的查询中的不透明偏移标记。我考虑过在函数上创建一个索引,该索引将 return 行的唯一数字位置,但我担心这会严重影响大 tables 的 INSERTs 和 UPDATEs 的时间,我认为有最佳解决方案。

虽然这对 ORDER BY {unique_field} 查询来说很简单 [2],但我没有看到对 non-unique 字段实现相同目的的简单方法。

我们还假设解决方案应该在 postgresql 和 mysql 中工作。


备注:

[1] 由于像 SELECT id, title FROM book ORDER BY title OFFSET [number] LIMIT [number] 这样简单的解决方案对于大的数字偏移值非常糟糕,我会引入某种不透明的标记这将代表我 API 中给定集合中用于获取书块的偏移量。

因此 API 方法 return 具有给定偏移量的按书名排序的书籍列表将如下所示(伪代码):

BookPage getBooks(optional string offsetToken, int limit)

其中 BookPage 定义如下:

class BookPage {
 nonnull List<Book> books;
 nonnull string offsetToken; // expected to be used to return a next page
}

使用示例,书 table 包含 2*N 本书:

// 1st call
BookPage page1 = getBooks(null, 2); // get first 2 books
BookPage page2 = getBooks(page1.offsetToken, 2); // get next 2 books
BookPage page3 = getBooks(page2.offsetToken, 2); // get next 2 books
//...
BookPage pageN = getBooks(pageN-1.offsetToken, 2); // get last 2 books

和一系列列表 page1.books、page2.books、... pageN.books 将生成按书名升序排列的图书列表。

[2] 例如:如果 getBooks API 将使用偏移量查询,其中书籍按 id(主键)排序,offsetToken 将是最后一本书的 id 和 getBooks [=53 的实现=] 看起来如下(伪代码):

BookPage getBook(optional string offsetToken, int limit) {
 Long startId = (offsetToken != null ? toLong(offsetToken) : null);
 page.books = (SELECT id, title FROM books 
               WHERE :startId IS null OR id>:startId
               ORDER BY id
               LIMIT :limit);
 page.offsetToken = toString(lastElementOf(page.books).id)
 return page;
}

到目前为止,我找到的最简单的解决方案是将 non-unique 列与主键结合使用。它使 select 查询稍微复杂化 - 例如对于原始问题,您需要编写类似 (title = :title AND id > :id) OR (title > :title) 的内容,其中:title 和 :id 构成 offsetToken(最后一项的标题和 id)。