It turns out that retrieving low level datastore entities that are stored memcache is painfully slow. Since objectify caches entities as the low level datastore Entity type, this results in poor performance when fetching many entities from memcache using objectify.
The real question is why is it slow to deserialize the Entity type from memcache? I put together a sample project to demonstrate the disparity in retrieving Entities from memcache vs plain strings or a simple Map.
Here's the code:
https://github.com/aleemstreak/perftest or the relevant file: https://github.com/aleemstreak/perftest/blob/master/src/com/rewardly/perftest/PerftestServlet.java
Also, I deployed it so you can see how big a difference this is in production: aleemsandbox.appspot.com/perftest . Its a naive profiler but it does show a huge disparity in performance. Refresh the page a few times to see the difference. Here is some sample output:
Storing String Data Test
-------------------------
generateData: 0ms
storeData: 10ms
fetchData: 9ms
Storing Map Data Test
-------------------------
generateData: 0ms
storeData: 21ms
fetchData: 92ms
Storing Entity Data Test
-------------------------
generateData: 69ms
storeData: 24ms
fetchData: 792ms
The first section shows the time it takes to store 1000 strings in memcache and then fetch it right back. The next example does the same for 1000 Map objects and finally the last example stores and retrieves 1000 low level Entity types. You can see the huge time increase to retrieve Entity types.
Any ideas why entities could be slow to deserialize from memcache?
UPDATE 1
Following a suggestion in one of the answers, I also logged the cumulative size of the objects being stored in memcache and the results no print them out. I also added one other test case - instead of storing an Entity directly, instead, I serialize the Entity to a byte[] myself first, then store it in memcache. Here are the results:
StringBenchmark
----------------
Average Fetch Time: 40.16ms
Fetch Size: 24.41KB
MapBenchmark
----------------
Average Fetch Time: 27.36ms
Fetch Size: 102.54KB
EntityBenchmark
----------------
Average Fetch Time: 1029.88ms
Fetch Size: 463.87KB
EntityPreSerializedBenchmark
----------------
Average Fetch Time: 218.82ms
Fetch Size: 490.23KB
Whats interesting here are the last two results. Although they are roughly the same size, it takes about 1/5 the time to fetch and deserialize the byte[] manually.
The code in the github repo has been updated and the deployed sample app also has the latest code so feel free to run this test there and see the results.