当结果低于查询限制时,数据存储区查询会花费太长时间

时间:2017-03-04 04:24:44

标签: google-app-engine google-cloud-datastore

我的应用程序与待办事项应用程序相当。在任何给定时间,有几个待处理任务分配给单个用户。有些用户有近2500个待处理的任务,有些只有2个。

当匹配查询的结果低于查询上应用的限制时,似乎数据存储区查询花费的时间太长。例如:

场景1:

用户A:有2500个待处理任务。查询限制为500,第一次请求获取的结果显然为500.所用时间:5767毫秒(5.7秒)。

用户B:有2个待处理任务。查询限制为500,第一次请求获取的结果显然为2.时间:7124毫秒(7.1秒)。

场景2:

用户A:有2500个待处理任务。查询限制为10,第一次请求获取的结果显然为10.所用时间:~400毫秒(1/2秒)。

用户B:有2个待处理任务。查询限制为10,第一次请求获取的结果显然为2.所用时间:5-6秒。

场景3:

用户A:有2500个待处理任务。查询限制为500,第一次请求获取的结果显然为500.所用时间:6244毫秒(6秒)。

用户C:有551个待处理任务。查询限制为500,第一次请求获取的结果显然为500.所用时间:13579毫秒(13秒)。

我的代码:

public static Map <String , Object> getEntitiesUsingQueryCursor( String kind , int limit , int chunkSize , String currentCursor, String account, String user, Boolean status, String dept ) throws Exception
        {

            String nextCursor = null;

            Entity entity = null;

            List <Entity> listOfEntity = new ArrayList <Entity>();

            Map <String , Object> result = new HashMap <String , Object>();


            DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
            com.google.appengine.api.datastore.Query q = new com.google.appengine.api.datastore.Query( kind );

List <Filter> listOfFilter = new ArrayList <Filter>();
Filter filter1 = new FilterPredicate( "account" , FilterOperator.EQUAL ,  account);
Filter filter2 = new FilterPredicate( "user" , FilterOperator.EQUAL ,  user);
Filter filter3 = new FilterPredicate( "dept" , FilterOperator.EQUAL ,  dept);
Filter filter4 = new FilterPredicate( "status" , FilterOperator.EQUAL ,  status); //Boolean
listOfFilter.add( filter1 );
listOfFilter.add( filter2 );
listOfFilter.add( filter3 );
listOfFilter.add( filter4 );
Filter filterParams1 = filterParams = CompositeFilterOperator.and( listOfFilter );
q.setFilter( filter );

            PreparedQuery pq = datastore.prepare( q );
            FetchOptions fetchOptions = FetchOptions.Builder.withLimit(limit).prefetchSize( chunkSize ).chunkSize( chunkSize );

            if ( !StringUtil.isBlank( currentCursor ) )
                fetchOptions.startCursor( Cursor.fromWebSafeString( currentCursor ) );

            QueryResultIterable <Entity> results = pq.asQueryResultIterable( fetchOptions );
            QueryResultIterator <Entity> iterator = results.iterator();

            while ( iterator.hasNext() )
                {
                    entity = iterator.next();
                    listOfEntity.add( entity );
                }

            if(listOfEntity.size() == limit)
                nextCursor = iterator.getCursor().toWebSafeString();

            result.put( "cursor" , nextCursor );
            result.put( "entity" , listOfEntity );

            return result;
        }

这是数据存储区查询的工作原理吗?有人可以提出更好的查询实体的方法吗?如果我在查询上设置了平均限制50,那么少于50个待处理任务的用户必须等待至少7秒才能在页面上完成任务。即使我将限制设置为10并且用户只有2个待处理任务,7秒时间也适用。

1 个答案:

答案 0 :(得分:1)

如果您在account,user,dept,status上定义composite index,则回答上述查询只需要对单个索引进行线性扫描,这样可以大大提高查询速度(无论限制如何)。

为了说明,假设你有      [row] [account, user, dept, status] [entity] 1] A B C D e1 2] A B E F e2 3] A B E F e3 4] A F A A e4 5] B A Z E e5 'A B E F'的查询会找到行[2],然后线性扫描到[3],返回[e1, e2]。它会在[4](不匹配的第一行)停止做很少的工作。