【发布时间】:2014-08-23 08:49:03
【问题描述】:
这应该是一个有趣的挑战。 我正在寻找一种尚不存在的算法(据我所知)
- 我们有一个数据库访问函数,可以一次读取多页记录,使用页码和页大小作为参数。让我们调用这个函数
getFromDatabase(int page, int size)。 - 我们希望提供一个 REST API,它应该根据偏移量和限制返回记录。让我们将其包装在一个函数
getRecords(int offset, int limit)中。
不知何故,我们必须使用给定的offset 和limit 来检索只能由page 和size 访问的匹配数据库记录。显然,偏移量/限制不会总是映射到单个页面/大小。挑战在于找到一种算法,使getFromDatabase 调用的“理想”数量能够检索所有记录。该算法应考虑几个因素:
- 每次调用
getFromDatabase都有一定的间接费用;尽量减少来电。 - 检索到的每条记录都会增加额外的开销;检索尽可能少的记录(如果可以减少总开销,则可以检索“浪费”)。
- 算法本身也有间接成本;显然,它们不应该超过任何好处。
我想出了以下算法:http://jsfiddle.net/mwvdlee/A7J9C/ (JS 代码,但算法与语言无关)。本质上是下面的伪代码:
do {
do {
try to convert (offset,limit) to (page,size)
if too much waste
lower limit by some amount
else
call `getDatabaseRecords()`
filter out waste records
increase offset to first record not yet retrieved
lower limit to last records not yet retrieved
} until some records were retrieved
} until all records are retrieved from database
该算法的关键在于确定too much waste 和some amount。但是这个算法不是最优的,也不能保证是完整的(很可能是这样,我只是无法证明)。
有没有更好的(已知的?)算法,或者我可以做的改进? 有人对如何解决这个问题有好的想法吗?
【问题讨论】:
-
可能,迄今为止最便宜的选择是只调用一次外部服务,因为按偏移量返回行通常需要扫描所有先前的行。这太贵了。与此相比,传输单行非常便宜。
-
@usr;也许我误解了;如果调用者没有该行的识别信息,为什么转移单行会更便宜?这不就像用
limit1 检索一样有效吗? -
我的意思是传输 11 行可能几乎与传输 10 行一样便宜,只要它作为一个查询的一部分发生。它并不贵 10%。更像是 0.1% 以上。
-
我假设在 DB 存储中分配了连续数量的记录(首先在 offset 处,最后在 offset+limit-1 处),但通常这不需要是从一些 DB 存储内存开始的块一些地址 a 并以 offset*recordsize 结尾。那么你怎么能希望用单个页面(无论如何给出这个值的“单位”)和任意大小(以字节为单位)来检索它?
-
@Martijn 如果有人向您请求 { offset = 25, limit = 10 },您不能只调用
getFromDatabase(page: 2, size: 20)并在一次调用中获取所有数据(并丢弃一些行)吗?这听起来不太难解决,所以我可能错过了一些要求。总是有可能构造一个最多浪费 50% 的调用。
标签: database algorithm limit offset