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)。
假设我有这样一个 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)。