Apc Caching

I’ve been searching for answers to some questions I have on APC Caching specifically related to CActiveRecord but was unable to find anything that really helped. What I found seemed murky, and there are a number of unanswered cries for help in this forum regarding this subject. Therefore I thought that it might be time to start up some discussions and clarify the mysteries.

What initiated my quest was my desire to do some query caching. I wanted to use APC, as all-around, it seemed to have the claims of best performance (when configured correctly). It looked straightforward enough at the start and I really didn’t have much trouble installing it on my VM (VirtualBox with Ubuntu 12.04). But then I became confused when I used the cache() method for a findAll query: the results were cached with no problem and they were retrieved with no problem, but then I got into using the dependency with no luck. Finally frustrated, I decided I would handle the caching myself using CApcCache’s get and set. Lo and behold, the query continued to be cached even though I removed the cache() method! So if I may, I would like to start the discussion with this:






This resulted in findAll getting cached by default, unless I added cached(0) to disable it. But I didn’t want to do that throughout the rest of the code as that would return stale data where it shouldn’t. I couldn’t find documentation as to why this was happening, then realized that is likely setting it as the default for the system. So I did this:






Voila! No more default caching and I could set and get what I wanted. I want to do more with this, however, perhaps some settings where some models will cache as the data may not change for long periods of time, but am a little stumped on how to progress. I was trying to override the cache() to use CApcCache and was only able to save to the cache and not serve from it.

I would love some input and I will add as much as I have figured out thus far and figure out as I work through my project.

Thanks in advance!

Hi Frank,

Yes, the management of the dependency is the key point in using cache.

You’d better go back to that point, discarding all the changes made after that. Don’t try to call ‘get’ and ‘set’ of CApcCache for query caching by yourself.

IMHO, what you have to do is just to understand how to work with cache dependency.

I agree, I did some testing with caching pages and used the dependency just fine it that instance. I must have been doing something wrong with the query caching. I’d like to ask this: Will the findAll query cache by default with the caching component in place?

By default, db connection component uses ‘cache’ component when it caches the query result.

It means that it uses the cache component whose name is ‘cache’. So when you use APC cache component with the name of ‘apcCache’ or something, then query cache doesn’t use APC. But if you have another cache component whose name is ‘cache’, then it will be used for the query caching.

And you can change it by setting the ‘queryCacheID’ property of the db component.


And, as I wrote, db connection doesn’t do any query caching without an explicit call to cache() method.


The query caching is a kind of data cache, and is performed in the level of db connection. It uses the SQL text (actually the hash of it) as the key to the cache entry. So when you execute the same SQL next time, it may be served from the cache, only if it’s not expired and the dependencies are not changed.

CActiveRecord::cache() method is a kind of utility function to call it.

One thing you may note is that you would be better clear the cache entries (especially "User Cache Entries") of APC every time when you want to test something new, in order to avoid strange results caused by the previously cached entries.

Thank you very much, softark!

Here’s a question about the frequency of a CDbCacheDependency check: Any time the cache is being checked and the hash matches, the dependency needs to be checked too. So that means there’s a DB hit for that SQL dependency every time, which I want to avoid for this specific instance. Does the duration take precedence over the dependency? If I set a duration of 3600 seconds, then the dependency will not be tested until the duration has expired. Is that correct?

Checking of a cache entry works like the following:

  1. Check for the existence of the cache entry, using a key for the entry.

… If it doesn’t exist, then abort.

  1. Check for the duration of the cache entry.

… If it’s expired, then the cache entry will be discarded.

  1. Check if the dependency have not been changed.

… If the dependency has been changed, then the cache entry will be discarded.

  1. Use the cache entry as a valid data.

Note that dependency information (some value and the way how to get it … e.g. some SQL result and the SQL itself) IS A PART of a cache entry.

So, as you might be worrying, a heavy SQL dependency may spoil the caching itself.

Excellent, I’ve been looking at the various dependency types to see which to leverage best.

I noticed at one point that when using DAO it appears to be caching the query. For example, I am executing the following:

return Yii::app()->db->createCommand($sql)->bindParam(':userId', $this->id)->queryScalar();

Without calling the cache() method, it’s saving and serving from the cache. That should not be happening as far as I understand. It’s not supposed to be caching by default. I realize, of course, I could use cache(0), but that’s troublesome to do that for every query. I would rather specify using the cache rather than as a default.

Thanks in advance for any answers!

AFAIK, the default behavior of db querying is without cache. Caching should happen only when you have explicitly called cache().

I guess it might be the schema cache that you have noticed.

That is my understanding, too, but the caching I was seeing was of the ‘saving’ and ‘serving’ variety, as I am currently not caching the schema. Bears a little looking into. Thanks for your help, softark!