首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在不影响性能的情况下获取App Engine数据存储查询中每个实体的游标?

如何在不影响性能的情况下获取App Engine数据存储查询中每个实体的游标?
EN

Stack Overflow用户
提问于 2018-07-23 07:41:50
回答 2查看 528关注 0票数 1

我有一个使用游标(Objectify v5)的数据存储查询,我希望在结果列表中的每一项之后获得游标。代码如下所示:

代码语言:javascript
复制
public List<Puzzle> queryWithCursor(String cursor, String order, int limit) {
  Query<Puzzle> query = ObjectifyService.ofy()
    .load()
    .type(Puzzle.class)
    .order(order)
    .limit(limit);
  query = query.startAt(Cursor.fromWebSafeString(cursor));
  List<Puzzle> puzzles = new ArrayList<>();
  QueryResultIterator<Puzzle> iterator = query.iterator();
  while (iterator.hasNext()) {
    Puzzle puzzle = iterator.next();
    puzzle.setCursor(iterator.getCursor().toWebSafeString());
    puzzles.add(puzzle);
  }
  return puzzles;
}

虽然该方法工作正常,但它在后台触发了如此多的数据存储查询。基本上,iterator.getCursor()每次运行时都会触发一个额外的查询。我从Stackdriver Trace中了解到,如果limit为20,则该方法总共触发19个查询(似乎最后一个.getCursor()不会触发额外的查询)。因此,这种方法比使用offset的类似查询速度更慢,成本更高。

这真的是一个bug吗?有没有办法避免对性能的影响?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-26 23:44:46

这实际上是数据存储的基本行为,至少在旧的sdk中是这样(与Objectify 6使用的新sdk相反,新sdk可能相同,也可能不同)。在非批处理边界调用getCursor()将重新启动查询。您可以使用低级API进行尝试。

有一个解决办法:创建您自己的游标类。它应该由低级光标和偏移量组成。显式设置区块大小,那么您的游标应该由索引0处的Cursor加上区块中的偏移量组成。

然后,当您想要在该游标上重新启动查询时,使用.cursor(batchStartCursor).offset(offsetIntoBatch)

票数 0
EN

Stack Overflow用户

发布于 2018-07-23 08:09:18

代码语言:javascript
复制
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.datastore.QueryResultList;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ListPeopleServlet extends HttpServlet {

  static final int PAGE_SIZE = 15;
  private final DatastoreService datastore;

  public ListPeopleServlet() {
    datastore = DatastoreServiceFactory.getDatastoreService();
  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    FetchOptions fetchOptions = FetchOptions.Builder.withLimit(PAGE_SIZE);

    // If this servlet is passed a cursor parameter, let's use it.
    String startCursor = req.getParameter("cursor");
    if (startCursor != null) {
      fetchOptions.startCursor(Cursor.fromWebSafeString(startCursor));
    }

    Query q = new Query("Person").addSort("name", SortDirection.ASCENDING);
    PreparedQuery pq = datastore.prepare(q);

    QueryResultList<Entity> results;
    try {
      results = pq.asQueryResultList(fetchOptions);
    } catch (IllegalArgumentException e) {
      // IllegalArgumentException happens when an invalid cursor is used.
      // A user could have manually entered a bad cursor in the URL or there
      // may have been an internal implementation detail change in App Engine.
      // Redirect to the page without the cursor parameter to show something
      // rather than an error.
      resp.sendRedirect("/people");
      return;
    }

    resp.setContentType("text/html");
    resp.setCharacterEncoding("UTF-8");
    PrintWriter w = resp.getWriter();
    w.println("<!DOCTYPE html>");
    w.println("<meta charset=\"utf-8\">");
    w.println("<title>Cloud Datastore Cursor Sample</title>");
    w.println("<ul>");
    for (Entity entity : results) {
      w.println("<li>" + entity.getProperty("name") + "</li>");
    }
    w.println("</ul>");

    String cursorString = results.getCursor().toWebSafeString();

    // This servlet lives at '/people'.
    w.println("<a href='/people?cursor=" + cursorString + "'>Next page</a>");
  }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51470091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档