Welcome Guest, Not a member yet? Register   Sign In
Cache Model interactions
#1
Lightbulb 

Not very sure about this but an idea that has arisen now studying how to use  MySQL with Memcached...

Normally the cache is checked and if returns false is done a query in the database and then saves it in the cache similar to this example in the user guide...

I think about the possibility that the Model already can do this automatically, having a property to configure the ttl of the cache.

And then all Model methods (find*, update, etc) automatically update the cache.
Reply
#2

Interesting idea, and reminds me of something we ripped out of the database layer from CI3 - the Query Caching feature. it wasn't used all that much from what we heard, and was the cause of a fair amount of un-needed complexity so we discarded it for CI4.

A much simpler method, as far as I am concerned, is to simply cache view fragments, so you never need to load up the database at all. Big performance gains that way, and doesn't add complexity on top of the db layer.
Reply
#3

Yes. It may be better to cache the view fragments.

But it might be nice to be able to manage the model results. I know we can do this the way it already is, but a conditional would have to be done for each get of the cache/db data.

I imagine the Model getting from the cache but simulating the same output it would have from the database. In order to be able to handle this data with other models.

In the inserts we could already allocate the data instantly in the cache if the data were inserted successfully in db. And analyze whether the ttl has expired or the results are not cached to return them in the selects. Also works in db updates, deletes acting in the cache. A model property could to enable and disable it and manage externally by some method.

I was modeling a database with a lot of foreign keys and I thought it would be hard to keep checking it all the time.
Reply
#4

While it might prove something in the future, it's a complication I don't think we want to tackle just yet. Let's revisit this after we actually get a release out the door. Smile
Reply
#5

hmm sounds interesting but isnt this the same as the mysql query cache do ? ( MySQL Query CacheGood Description )
well i know its a bit slower, maybe we should play around with it before creating another cache-layer
Reply
#6

(01-03-2018, 04:15 AM)puschie Wrote: hmm sounds interesting but isnt this the same as the mysql query cache do ? ( MySQL Query CacheGood Description )
well i know its a bit slower, maybe we should play around with it before creating another cache-layer

Not exactly the same. More like the Percona post says about Memcached.

This could optimize performance to do relationships in Model, like:

PHP Code:
<?php namespace App\Models\Blog;

use 
CodeIgniter\Model;
use 
App\Models\Admin\Users;

class 
Posts extends Model
{
    protected 
$table         'blog_posts';
    protected 
$allowedFields = [
        
'author_id',
        
'title',
        
'content',
    ];
    protected 
$afterFind     = ['getAuthor'];

    protected function 
getAuthor($data)
    {
        if (isset(
$data['data']['id']))
        {
            
$users = new Users;

            
$data['data']['author'] = $users->find($data['data']['author_id']);
        }

        return 
$data;
    }




By this way a cache item identified by the key prefix:App:Models:Admin:Users:5 could be setted and in the next finds this relationship will get data from the cache.

If the Admin User ID 5 is updated with success in the DB, than cache is updated.

The same can be run with the Post when get. Then, what would be two queries (or more if Models do "relationship") will be none.

And the results of the Cache and DB always will be synchronized by the default Models methods.
Reply
#7

(This post was last modified: 01-15-2018, 04:38 PM by natanfelles. Edit Reason: typo )

[Image: p2CybXB.png]
As this example image, the following process can occurs when get a post:
  • Get the Post(s) and save it to the cache
  • Can have an afterFind Event and return the author on the fly
  • Can return the the X newest comments
  • In the Comments model can return an associative array with child comments
Then the $posts->find(5) will return:


PHP Code:
[
 
   'id'        => '5',
 
   'author_id' => '2',
 
   'title'   => '...',
 
   'content'   => '...',
 
   'author'    => [/* Author fields */ ],
 
   'comments'  => [
 
       [/* comment x */],
 
       [/* comment y */],
 
   ],
 
  'created_at' => '...',
 
  'deleted_at' => '...',




First find some queries will put every item in the cache. In the next, it get from the cache and update with a query result if necessary.

I do not found an way to manage results using the query builder before the finds, like "select(['id'])->find(5)" yet. Then the best to do, I think, is put all the table fields in the cache. Turning it "alive".

Inspiration:

- http://highscalability.com/blog/2010/5/1...-page.html
Reply
#8

Implementing: Now is more easy to do that.

On the specific use-case of saving the model entities results on the cache could be started as:

PHP Code:
<?php namespace App\Models;

use 
CodeIgniter\Model as BaseModel;

class 
Model extends BaseModel
{
    protected 
$cachePrefix 'modelEntity';
    protected 
$cacheTtl    120;

    public function 
find($id)
    {
        
$cache_key $this->getCacheKey($id);

        if (! 
$data cache($cache_key))
        {
            
$data parent::find($id);

            
cache()->save($cache_key$data$this->cacheTtl);
        }

        return 
$data;
    }

    public function 
insert($databool $returnID true)
    {
        
$result parent::insert($data$returnID);

        if (
$result === true || $returnID && is_numeric($result))
        {
            
$cache_key $this->getCacheKey($this->db->insertID());

            
$data parent::find($this->db->insertID());

            
cache()->save($cache_key$data$this->cacheTtl);
        }

        return 
$result;
    }

    public function 
update($id$data)
    {
        
$result parent::update($id$data);

        if (
$result === true)
        {
            
$cache_key $this->getCacheKey($id);

            
$data parent::find($id);

            
cache()->save($cache_key$data$this->cacheTtl);
        }

        return 
$result;
    }

    public function 
delete($id$purge false)
    {
        
$result parent::delete($id$purge);

        if (
$result === true)
        {
            
cache()->delete($this->getCacheKey($id));
        }

        return 
$result;
    }

    protected function 
getCacheKey($id)
    {
        return 
$this->cachePrefix ':' str_replace('\\'':'get_class($this)) . ':' $id;
    }



Then, just extends the custom Model...

PHP Code:
<?php namespace App\Models\Blog;

use 
App\Models\Model;
use 
App\Models\Admin\Users;

class 
Posts extends Model
{
    protected 
$table 'blog_posts';
    
//protected $returnType    = 'App\Entities\Blog\Post';
    
protected $allowedFields = [
        
'author_id',
        
'title',
        
'description',
        
'content',
        
'image',
        
'meta_keywords',
        
'meta_description',
    ];

    protected 
$afterFind       = [
         
'getAuthor',
    ];


    protected function 
getAuthor($data)
    {
        if (isset(
$data['data']['id']))
        {
            
$users = new Users;

            
$data['data']['author'] = $users->limit(1)->find($data['data']['author_id']);
        }

        return 
$data;
    }


Reply




Theme © iAndrew 2016 - Forum software by © MyBB