Paging, listing and grouping queries with AppFabric Cache

1.5k views Asked by At

I read a lot of documents about AppFabric caching but most of them cover simple scenarios. For example adding city list data or shopping card data to the cache. But I need adding product catalog data to the cache.

I have 4 tables:

Product (1 million rows), ProductProperty (25 million rows), Property (100 rows), PropertyOption (300 rows)

  • I display paged search results querying with some filters for Product and ProductProperty tables.
  • I am creating criteria set over searched result set. For example (4 Items New Product, 34 Items Phone, 26 Items Book etc.)
  • I query for grouping over Product table with columns of IsNew, CategoryId, PriceType etc.
    and also another query for grouping over ProductProperty table with PropertyId and PropertyOptionId columns to get which property have how many items

Therefore to display search results I make one query for search result and 2 for creating criteria list (with counts)

Search result query took 0,7 second and 2 grouping queryies took 1,5 second in total. When I run load test I reach 7 request per second and %10 dropped by IIS becasue db could not give response.

This is why I want to cache Product and property records.

If I follow items below (in AppFabric);

  • Create named cache
  • Create region for product catalog data (a table which have 1 million rows and property table which have 25 million rows)
  • Tagging item for querying data and grouping.

Can I query with some tags and get 1st or 2nd page of results ? Can I query with some tags and get counts of some grouping results. (displaying filter options with count) And do I have to need 3 servers ? Can I provide a solution with only one appfabric server (And of course I know risk.) Do you know any article or any document explains those scenarios ?

Thanks.

Note:

Some additional test: I added about 30.000 items to the cache and its size is 900 MB. When I run getObjectsInRegion method, it tooks about 2 minutes. "IList> dataList = this.DataCache.GetObjectsInRegion(region).ToList();" The problem is converting to IList. If I use IEnumerable it works very quicly. But How can I get paging or grouping result without converting it to my type ?

Another test:

I tried getting grouping count with 30.000 product item and getting result for grouping took 4 seconds. For example GetObjectByTag("IsNew").Count() and other nearly 50 query like that.

1

There are 1 answers

1
Drew Marsh On

There is, unfortunately, no paging API for AppFabric in V1. Any of the bulk APIs, like GetObjectsByTag, are going to perform the query on the server and stream back all the matching cache entries to the client. From there you can obviously use any LINQ operators you want on the IEnumerable (e.g. Skip/Take/Count), but be aware that you're always pulling the full result set back from the server.

I'm personally hoping that AppFabric V2 will provide support via IQueryable instead of IEnumerable which will give the ability to remote the full request to the server so it could page results there before returning to the client much like LINQ2SQL or ADO.NET EF.

For now, one potential solution, depending on the capabilities of your application, is you can actually calculate some kind of paging as you inject the items into the cache. You can build ordered lists of entity keys representing each page and store those as single entries in the cache which you can pull out in one request and then individually (in parallel) or bulk fetch the items in the list from the cache and join them together with an in-memory LINQ query. If you wanted to trade off CPU for Memory, just cache the actual list of full entities rather than IDs and having to do the join for the entities.

You would obviously have to come up with some kind of keying mechanism to quickly pull these lists of objects from the cache based on the incoming search criteria. Some kind of keying like this might work:

private static string BuildPageListCacheKey(string entityTypeName, int pageSize, int pageNumber, string sortByPropertyName, string sortDirection)
{
   return string.Format("PageList<{0}>[pageSize={1};pageNumber={2};sortedBy={3};sortDirection={4}]", entityTypeName, pageSize, pageNumber, sortByPropertyName, sortDirection);
}

You may want to consider doing this kind of thing with a separate process or worker thread that's keeping the cache up to date rather than doing it on demand and forcing the users wait if the cache entry isn't populated yet.

Whether or not this approach ultimately works for you depends on several factors of your application and data. If it doesn't exactly fit your scenarios maybe it will at least help shift your mind into a different way of thinking about solving the problem.