2017-03-04 28 views
1

我有一個與待辦事項應用程序相當的應用程序。在任何特定時間都有幾個未分配任務分配給單個用戶。某些用戶有近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秒。

+0

猜測,您的查詢必須掃描每個過濾器的一個索引。查看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匹配,查詢引擎將在返回之前讀取每個可能匹配的記錄。因此,具有大於匹配數量的限制的查詢將保證具有最差的性能。 然後問題就變成了,這怎麼可以減輕呢?一個可能的答案是在最糟糕的情況下制定指標以最大限度地提高績效。另一個答案是取消限制,但我認爲這不是一個選項。 – snakecharmerb

回答

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](不匹配的第一行)做了很少的工作。