2017-03-04 7 views
1

To-doアプリに匹敵するアプリケーションがあります。一度に1人のユーザに割り当てられたいくつかの保留中のタスクがあります。一部のユーザーには約2500件のタスクが保留中であり、一部のユーザーには2件しかありません。結果がクエリの制限よりも小さい場合、Datastoreクエリが時間がかかりすぎる

クエリに一致する結果がクエリに適用される制限よりも低い場合、データストアクエリに時間がかかりすぎるようです。例:

シナリオ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秒間が適用されます。

+0

推測すると、クエリは各フィルタの1つのインデックスをスキャンする必要があります。インデックスがクエリの掲載結果に与える影響を確認するには、https://cloud.google.com/appengine/articles/indexselection#Performanceをご覧ください。 – snakecharmerb

+0

@snakecharmerbクエリの制限が10で、フィルタに一致する結果が2500を超える場合、待ち時間は400ミリ秒です。同じクエリを適用し、フィルタに一致する結果が2(制限値10未満)である場合、かかる所要時間は5-6秒です。それは本当にインデックスについてですか? – Kumar

+0

それは可能性があります。データストアで10と2500以上の制限が一致すると、照合エンジンは一致が10件見つかるとクエリを停止できます。データストアで10と2の制限が一致すると、照会エンジンは一致する可能性のあるすべてのレコードを読み取り、返されます。したがって、一致の数よりも大きい制限を持つクエリは、最悪の場合のパフォーマンスを持つことが保証されます。 次に、問題はどのように緩和されますか? 1つの可能な答えは、最悪の場合にパフォーマンスを最大化するためのインデックスを作成することです。もう一つの答えは、制限を削除することですが、私はそれがオプションではないと仮定します。 – snakecharmerb

答えて

1

上記のクエリに答えるaccount,user,dept,statuscomposite indexを定義した場合、クエリの速度を大幅に向上させる単一のインデックスのリニアスキャンが必要になります(制限にかかわらず)。説明するために

は、あなたが'A B E F'ためのクエリが[e1, e2]を返す[3]に行[2]、その後、リニアスキャンを見つけるだろう [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 を持っていたとします。それは非常に小さな仕事をした[4](一致しない最初の行)で停止します。

関連する問題