偏移查询非唯一列

时间:2015-04-09 06:27:20

标签: sql offset

假设我有一张这样的表:

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

我希望支持带偏移量的查询,以支持返回图书清单的API,按照非唯一标题字段排序并给定偏移和限制。

这里的问题是为非唯一title列定义唯一索引(或辅助列或类似内容)的最有效方法[1],该列可用作不透明偏移标记查询我正在使用的ORDER BY title。我想过在函数上创建的索引会返回行的唯一数字位置,但我担心这会严重影响大表的INSERT和UPDATE的时序,我认为有一个最佳的解决方案。

虽然这对于ORDER BY {unique_field}查询来说很简单[2]但我看不到为非唯一字段实现相同的简单方法。

另外我们假设解决方案应该在postgresql和mysql中运行。


注意:

[1]由于直接的解决方案,如SELECT id,title FROM book ORDER BY title OFFSET [number] LIMIT [number]对于大数值偏移值的工作非常糟糕,我会介绍一些代表偏移量的不透明令牌我的API中的给定集合用于获取图书块。

因此API方法将返回按标题排序并具有给定偏移量的书籍列表,如下所示(伪代码):

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
}

使用示例,书籍表包含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 API的实现将如下所示(伪代码):

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;
}

1 个答案:

答案 0 :(得分:0)

到目前为止,我发现的最简单,最简单的解决方案是将非唯一列与主键结合使用。它使选择的查询稍微复杂化 - 例如对于原始问题,你需要写一些类似(title =:title AND id&gt;:id)OR(title&gt;:title),其中:title和:id构成offsetToken(最后一项的标题和id)。