Cactiverecord And Caching

Here are few problems that i faced with CActiveRecord and my proposed outlines for solutions. These are by no means efficient so i look forward to your suggestions for improvements.

[size="3"]Problem #1:[/size]

In same request i use findAll() or similar methods with "select *" and later i use another findAll() with same condition but a different select. In this case we would have 2 queries issued to database.

[size="2"]Proposed Solution outline:[/size]

a- Inside beforeFind check if a cached model exists that

i- has same condition

ii- contains all columns requested in "select" for current query

b- Inside afterSave check if a cached copy for this model already exists:

i- If it does then update individual properties

ii- If it doesn’t then cache the model

[size="3"]Problem #2:[/size]

Even though findAll() or similar methods have been executed for the said record in past (in previous or current request) if we need to access couple of properties of a model in a place where earlier fetched object isn’t available we would have to query again.

[size="2"]Proposed Solution outline:[/size]

a- Update the solution of Problem #1 to support querying properties from cached models with keys like:


For keys that aren’t cached, query them and add them to cached copy of model.

[size="3"]Problem #3:[/size]

When using lazy loading and trying to access related records we would see duplicate queries for records with same related object. Consider 2 tickets with same reporter object fetched using lazy loading. when we iterate over the tickets array and dump reporter for each ticket we would see 2 queries for same user record.

[size="2"]Proposed Solution outline:[/size]

a- Override getRelated() and check with the model cache implemented in Problem #1’s solution against the value of foreign key.

i- If the record exists, reply with it.

ii- If it isn’t then go on with parent::getRelated() and let CActiveRecord handle getRelated. Even in this approach the fetched related object would be cached due to afterFind’s override in Problem #1’s solution.


1- It could cache sensitive data such as user’s password, etc which shouldn’t be cached. We could counter this by using a property, called $skipCacheForAttributes which would be array listing of properties to never cache, in all children classes.

2- It could cache a lot of data. Think of ticket messages that have TEXT db column. We could again skip these by using a method described above.

3- With the number of growing records we could:

a- overrun cache space(we are saving serialized models, not just properties), specially for APC/Memcache so using FileCache would be more appropriate perhaps. A sweeper process should also be implemented to clear all caches not accessed within a certain time.

b- lose the performance edge that we are trying to achieve by not communicating with remote mysql. With a lot of cached data it could take almost same time to fetch from cache vs querying it from remote mysql, perhaps even slow in some cases. An example of being slower could be when we are querying ticket updates and all properties except ticket_message would be retrieved from cache while for ticket_message we would still have to query db.

So to sum it up i am not sure how worthy it would be to invest time on this. I have been wondering over these problems for quite some time but this is the best i could come up with. This isn’t implemented, just few ideas, some outlines on possible workarounds.

As far as I understand, the current implementation of query cache doesn’t have any reference to AR objects. It has nothing to do with ‘beforeFind’ or ‘afterSave’, or something specific to AR. It is SQL/DAO based, not AR based. So it works fine with DAO, and it works fine too with AR via DAO.

IMO, what you are thinking is a completely different implementation of AR that has a built-in mechanism of caching. It’s an interesting approach, but … well, I don’t think it’s very promising in Yii, especially with the current implementation of AR.

As you have already noticed, too much sophistication and complication will choke up the caching itself.