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秒間が適用されます。
推測すると、クエリは各フィルタの1つのインデックスをスキャンする必要があります。インデックスがクエリの掲載結果に与える影響を確認するには、https://cloud.google.com/appengine/articles/indexselection#Performanceをご覧ください。 – snakecharmerb
@snakecharmerbクエリの制限が10で、フィルタに一致する結果が2500を超える場合、待ち時間は400ミリ秒です。同じクエリを適用し、フィルタに一致する結果が2(制限値10未満)である場合、かかる所要時間は5-6秒です。それは本当にインデックスについてですか? – Kumar
それは可能性があります。データストアで10と2500以上の制限が一致すると、照合エンジンは一致が10件見つかるとクエリを停止できます。データストアで10と2の制限が一致すると、照会エンジンは一致する可能性のあるすべてのレコードを読み取り、返されます。したがって、一致の数よりも大きい制限を持つクエリは、最悪の場合のパフォーマンスを持つことが保証されます。 次に、問題はどのように緩和されますか? 1つの可能な答えは、最悪の場合にパフォーマンスを最大化するためのインデックスを作成することです。もう一つの答えは、制限を削除することですが、私はそれがオプションではないと仮定します。 – snakecharmerb