CDbCacheDependency handling multirequest

If you are using CDbCacheDependency to invalidate cache,

sometimes you need use same dependency (or even chainedDependency)

several times through application.

But then CDbCacheDependency makes sql request to create dependent data, it disables yii query caching,

so even if you have one instance of dependency, how many cache validation checks

you are making - the same numbers of requests are sends to db server.

Its not a trouble at all if your db server has own query caching,

but if its not, you can make simple extending to CDbCacheDependency

to avoid repetitive queries:

UPD:

This code will work correctly.




class YoursDbCacheDependency extends CDbCacheDependency

{

	private static $_query_results=array();


	public function generateDependentData()

	{

		if (!isset(self::$_query_results[$this->sql]))

			return self::$_query_results[$this->sql]=parent::generateDependentData();

		else

			return self::$_query_results[$this->sql];

	}

}



I wonder if this should be a configuration option for CCacheDependency in general (e.g. public $reuseDependentData=false;). It could make sense for every kind of dependency to call generateData() only once and then store the result throughout the request. What do you think?

Agree.

And more, i think better reuse result of getHasChanged(), to avoid unneeded repeat of comparison.

Also, i can’t find any real reason why this should’t be done by default for CDbCacheDependency.

I would say, open a issue at google code: http://code.google.com/p/yii/

I’m not sure I follow you on this…

As you wrote above "how many cache validation checks you are making - the same numbers of requests are sends to db server."

For me that makes sense… for example lets say that I have to compute a database very resource intensive operation on all the table records… in that case I decide to use the cache and as a dependency I put count(*)… so if there is a new record in the table the resource intensive operation needs to be done again…

For me it makes sense to check if there is a new record every time I need that operation result… as anybody could have added a new record at the same time… especially on very high traffic websites…

By introducing the reusing of dependent data we are in fact caching the cache dependency… then why use a dependency… you can just cache it for any time you need it…

@mdomba: I think he talks about 1 request. The dependency is re-evaluated even i the same dependency object is reused during 1 request.

still not getting it… in any case where you want the "operation result"… you need to re-evaluate the dependency… even if there has been passed few seconds a new record could have been inserted… be that dependency in one request or more… it has to be re-evaluated…

why would we use the dependency if we want to cache it’s value? and when would be again re-evaluated?

The dependency result is not cached! It’s only evalutated once at the beginning of the reuqest. Say you have a dependency that queries if a blog post table has updated. And you reuse this same dependency on 2 locations for a fragment cache. You don’t want to send that same query 2 times to your DB in the same request.

2mdomba

Agree with you, sometimes its needed not cache the result of dependency, but

As said mike, i mean using one instance of CDbCacheDependency through application during single request.

For example if at the application i needs to validate cache of few elements (like widgets) by

sql query, but i don’t wan’t to create own instance of CDbCacheDependency for all of them.

Then i create only one instance, but every call of getHasChanged() is still makes query.

I mean this.

This also can be done by using together query result and CGlobalStateCacheDependency (or CExpressionDependency)

but i think this is not the best solution.

2mike

Done:

http://code.google.com/p/yii/issues/detail?id=2837

@Mike

My thinking is that I want to send the same query as the dependency could have changed in the meantime even during the same request… at least I’m using this feature in very high traffic sites where this is important…

but maybe there are other users that would like the option to not do that…

@Evgeny L

I would be interested to see how are you re-using the dependency in different widgets… are you passing it as a parameter?

@mdomba:

Actually i can’t really follow your scenario: How can it be that a dependency changes while e.g. you render one single view file? If some fragment cache snippet has the same dependency like another in the same view (e.g. blog was posted), why would you ever want different results for the same dependency during 1 request?

It’s just a way of using this feature…

I’m using it only for resource intensive operations… like some statistics computations / data analyzing on big tables… so those queries are a bit long… and the dependency “can” change between two calls… it just can happen :D… .and it happens at times…

But again I don’t have a real case scenario where I would re-use the dependency ;)

I have a very common one for you: :)

Think of a forum, with 2 boxes somewhere: Latest Posts and Most Active Authors. Both depend on the same query: Is there a new forum post?

That’s what I’m asking for… a real life example :D

in that case it is not even important if there is a new post… but again as I’m mostly using CDbCache I would not even cache that requests…

and again those would be rendered by different widgets too,

so for the same dependency I would need to pass the dependency object as a parameter to the widget… I personally dont like that idea… as there should be additional code in the widget for checking if the dependency is set or not…

controller




$this->isNewPost=new CDbCacheDependency(...);



view




<?php if($this->beginCache('latestPost', array('dependency'=>$this->isNewPost))) { ?>

...Latest Posts...

<?php $this->endCache(); } ?>

....

<?php if($this->beginCache('mostActiveAuthors', array('dependency'=>$this->isNewPost))) { ?>

...Most Active Authors...

<?php $this->endCache(); } ?>



If you will not reuse result of $this->isNewPost->getHasChanged() then you will make 2 identical querys to database.

Is there better solution?

Why don’t just use widgets $this->getOwner()->param if dependency may be used many times at controller?