2011-05-17 62 views
2

我有一个相当简单的App Engine Java应用程序,它具有Accounts,Orders和OrderItems - 没有什么疯狂的。简单的Google App Engine数据存储操作耗时过长:导致DeadlineExceededException/DatastoreTimeoutException

就在过去的12个小时里,我已经开始从一些相当直接的代码中抛出异常,这些代码将订单添加到帐户然后保存它们。

我创建了一个简单的测试servlet来复制这个问题,它看起来像这样:

public void doGet(HttpServletRequest req, HttpServletResponse resp) 
    throws IOException { 

     String key = req.getParameter("key"); 

     PersistenceManager pm = PMF.get().getPersistenceManager(); 
     Account account = pm.getObjectById(Account.class, KeyFactory.stringToKey(key)); 

     Order order = new Order(); 
     order.setExternalOrderID("ASHLEY-TESTING"); 

     Item item = new Item(); 
     item.setSku("ASHLEY-WIDGET-A"); 
     item.setQuantity(2); 
     Item item2 = new Item(); 
     item2.setSku("ASHLEY-WIDGET-B"); 
     item2.setQuantity(2); 

     order.addItem(item); 
     order.addItem(item2); 

     account.addOrder(order); 
     order.setAccount(account); 
     pm.makePersistent(order); 
     pm.close(); 
    } 

addOrder is implemented as a pretty standard lazy init: 

    public void addOrder(Order order) { 
     if (getOrders() == null) { 
      setOrders(new ArrayList<Order>()); 
     } 
     getOrders().add(order); 
    } 

The relevant parts of the entities: 

@PersistenceCapable 

public class Account { 

//... 

@Persistent(mappedBy="account") 
@javax.jdo.annotations.Order(extensions = @Extension(vendorName="datanucleus", key="list-ordering", value="orderDate desc")) 
private List<Order> orders; 

//... 

} 

and the Order has an account field: 

    @Persistent 
    private Account account; 

该代码失败在account.addOrder()线。如果它直接在浏览器中运行,它将以DeadlineExceededException(30秒之后)失败,如果我通过任务队列排队它,它将在一两分钟后失败,并出现DatastoreTimeoutException。它在此过程中使用卡车装载的CPU时间。

我估计帐户下的订单数少于2000个,每个订单有1-3个OrderItem子。

我的问题是,为什么会突然开始失败,它已经在那里添加了1000个订单。我错过了一些重要的东西吗?我需要添加索引吗?数据存储真的会这么慢吗?我是否在滥用它,如果我没有孩子与这么多孩子的关系 - 也许一组键会是一个更好的方法?

回答

0

在谷歌应用程序引擎幻灯片中,它提到,对于列表属性,数据存储性能会比较差,而项目编号大于“500”。这张幻灯片非常陈旧,我不确定现在的限制还是一样,但这可能是您的情况所存在的问题。并且不要在列表属性中存储太多项目是有意义的。在该幻灯片中,它建议用户在这种情况下使用扩展类。例如:

class Orders: 
    Account account // the account these order belong to. 
    List<Order> orders // the orders, limit to 500 items 

如果您有超过500个订单,只需添加另一个订单实例即可。

0

我都赞成查询接口这样的使用getOrders()停止:

Query query = pm.newQuery(Order.class); 
    query.setFilter("account == accountKey"); 
    query.declareParameters(Key.class.getName() + " accountKey"); 
    query.setOrdering("orderDate desc"); 
    query.setRange(0, numOrders); 

和将订单账目,我简单地设置一个新的秩序parent属性,坚持它,GAE手柄创建密钥并将其关联到父级。

  order.setAccount(account); 
      pm.makePersistent(order); 

我从GAE/J集团在这里的一些提示: http://groups.google.com/group/google-appengine-java/browse_thread/thread/6011d08025398254#

此外,lucemia的建议会的工作,但棘手的管理我觉得代码。

相关问题