一尘不染

分页与批处理查询?是否可以从数据存储中批处理获取并获取游标?

go

我目前正在从数据存储区中请求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时我看不到获取光标的方法,或者我错过了什么吗?

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


阅读 175

收藏
2020-07-02

共1个答案

一尘不染

您的方法非常好,实际上,这是AppEngine上的最佳方法。

如果插入了一条新记录(例如第一个记录),则通过设置开始光标来查询后续实体不会给您重复的结果。

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

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

也使用forappend()是最好的方法。您可以通过预先创建足够大的切片来对其进行一些优化:

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

但是请注意,我故意这样做是出于0长度和limit容量的考虑:不能保证会有足够的实体来填充整个切片。

另一个优化是将其分配为limitlength:

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
}

批量操作

GetMultiPutMulti并且DeleteMulti是的批量版本GetPutDelete功能。它们采用[]*Key而不是*Key,并且appengine.MultiError在遇到部分故障时可能会返回。

批处理操作不是查询的替代或替代。GetMulti例如,要求您已经准备好要获取完整实体的所有键。因此,这些批处理操作没有任何游标意义。

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

查询和批处理操作是针对不同的事物的。您不必担心查询和游标的性能。它们做得很好,而且重要的是,它们(数据存储区)可扩展。游标不会降低查询的执行速度,带游标的查询的运行速度与没有游标的查询一样快,并且先前返回的实体也不会影响查询的执行时间:是否运行查询都没有关系没有游标或拥有一百万个实体后获得的游标(只能通过多次迭代获得)。

2020-07-02