使用批处理查询进行分页?是否有可能从数据存储中批量获取并获取游标



我目前正在从数据存储中请求20个条目,将这些条目与游标一起返回给用户,如果用户要求更多条目,则使用游标作为新的开始并请求下一个20个条目。

代码看起来像
q := datastore.NewQuery("Item").
    Limit(limit)
if cursor, err := datastore.DecodeCursor(cursor); err == nil {
    q = q.Start(cursor)
}
var is []Item
t := q.Run(c)
for {
    var i Item
    _, err := t.Next(&i)
    if err == datastore.Done {
        break
    }
    is = append(is, i)
}

如果它很重要,这里是完整的代码:https://github.com/koffeinsource/kaffeeshare/blob/master/data/appengine.go#L23

它看起来是一个反模式使用循环与append,但我没有看到一个方法来获得一个光标时使用GetMulti/GetAll或我错过了什么?

我确实希望在用户查询数据存储时添加数据,因此偏移可能会产生重复的结果。在这种情况下,我应该关心批处理get吗?

你的方法非常好,事实上,这是AppEngine上最好的方法。

通过设置起始游标来查询后续实体,如果插入新记录(例如第一个记录),则不会得到重复的结果。

为什么?因为游标包含最后返回的实体编码的键,而不是之前返回的实体的数量。

因此,如果您设置了一个游标,数据存储将开始列出并返回在游标中编码的键之后的实体。如果保存了光标后面的新实体,则到达该实体时将返回该实体。

同时使用forappend()是最好的方法。您可以通过事先创建一个足够大的切片来稍微优化它:

var is = make([]Item, 0, limit)

但请注意,我故意使用0长度和limit容量:不能保证有足够的实体来填充整个切片。

另一个优化是将其分配为limit长度:

var is = make([]Item, limit)

,当到达datastore.Done时,如果没有完全填充,则重新切片,例如:

for idx := 0; ; idx++ {
    var i Item
    _, err := t.Next(&i)
    if err == datastore.Done {
        if idx < len(is) {
            is = is[:idx] // Reslice as it is not filled fully
        }
        break
    }
    is[idx] = i
}

批量操作

GetMultiPutMultiDeleteMultiGetPutDelete函数的批处理版本。它们接受[]*Key而不是*Key,并且在遇到部分失败时可能返回appengine.MultiError

批处理操作不能替代或替代查询。例如,GetMulti要求您已经准备好要获得完整实体的所有密钥。因此,对于这些批处理操作来说,没有游标的意义。

批处理操作返回所有请求的信息(或执行所有请求的操作)。没有实体或操作序列将/可以被终止并稍后继续。

查询和批处理操作是不同的。您不应该担心查询和游标性能。它们做得很好,重要的是,它们(数据存储)的可扩展性很好。游标不会减慢查询的执行速度,有游标的查询与没有游标的查询运行速度一样快,并且先前返回的实体也不会影响查询的执行时间:无论您是在没有游标的情况下运行查询,还是在获得一百万个实体后获得游标(这只有通过几次迭代才能实现)。

最新更新