Useridentity Query Db On Every Request

Hello,

I noticed that the framework does user identity check (query for user) on every request.

Like when I have a page, which uses 1 query on a page call and 3 ajax calls to fully load the page information I get 4 queries like this:




SELECT * FROM `users` WHERE `id`='1'



So I get 8 queries instead of 4 or 5.

Is that the way it should be? Or am i doing something wrong

I’m using the Users model representing users table in database for user identity check.




<?php


namespace app\models;


use yii\db\ActiveRecord;

use \yii\web\IdentityInterface;


class Users extends ActiveRecord implements IdentityInterface

{

	public $authKey;


	public function attributeLabels()

	{

		return [

			'id' => 'ID',

			'name' => 'Name',

			'surname' => 'Surname',

			'email' => 'Email',

                        'pass' => 'Pass'

		];

	}


	public static function findByUsername($username)

	{

		return static::find()->where(['email' => $username])->one();

	}


	public static function findIdentity($id)

	{

		return static::find()->where(['id' => $id])->one();

	}


	public function getId()

	{

		return $this->id;

	}


	public function getAuthKey()

	{

		return $this->authKey;

	}


	public function validateAuthKey($authKey)

	{

		return $this->authKey === $authKey;

	}

}




Technically, ajax call is independent request, so permisions must be checked every time.

I suppose you can use cache to avoid this.

Well I’m very unexperienced with cache thing, but this is my try:




public static function findByUsername($username)

{	

	$user = static::find()->where(['email' => $username])->one();


	if($user)

	{

		$session = new CacheSession();

		$session->writeSession('identity_' .$user['id'], $user);

	}


	return $user;

}


public static function findIdentity($id)

{

	$session = new CacheSession();

	$user = $session->readSession('identity_' .$id);


	if($user)

		return $user;

	else

		return static::find()->where(['id' => $id])->one();

}



But I think FileCache isn’t the best place to keep user identity?

CacheSession is for storing session data in a cache. You are not using it the correct way and it is also not ment to be used in this case.

Check the guide on caching:

https://github.com/yiisoft/yii2/blob/master/docs/guide/caching.md#data-caching

So I should simply do so:




public static function findByUsername($username)

{       

        $user = static::find()->where(['email' => $username])->one();


        if($user)

        {

             \Yii::$app->cache->set('identity_'.$user['id'], $user);

        }


        return $user;

}


public static function findIdentity($id)

{

        $user = \Yii::$app->cache->get('identity_'.$id);


        if($user)

                return $user;

        else

                return static::find()->where(['id' => $id])->one();

}



?

Looks more correct.

I’m not a fan of storing entire objects in the cache, as some objects can be really huge.

A better way to do this may be to store the attributes and recreate the object




\Yii::$app->cache->set('identity_'.$user['id'], $user->getAttributes());

...

if ($attributes = \Yii::$app->cache->get('identity_'.$id)) {

    $user = User::create($attributes);

}



Caching needs careful planning. How many times your application needs a specific data or sets of data? As amnah mentioned, you need to also consider the caching object size.

Basically, evaluate the costs of performance impact to understand what to cache first?

One other thing very very important is USER Experience. Caching can be great for performance, but may impact user experience, if you do not put the dependency right to reset the cache.

Kartik V gave some high level advice, but I think you’d do better with some real, practical advice.

Stop caching. Completely. Stop it right now, because you don’t need it.

I know what you’re thinking. I know how you feel, I’ve been there. It’s so inefficient to be making the same call on every page, surely this can be done better!

That’s true. But here’s the reality of it: Those basic select statements? They’re nothing. Short, simple, few, efficient, and optimized via your db. They don’t need to be cached.

So when should I cache then?

It’s simple! Just follow this great checklist my mentor gave me.




1) Don't cache anything

2) Wait until website becomes slow

3) Identify bottlenecks 

4) Fix bottlenecks by optimizing the algorithms

5) Algorithms optimized? Now you start caching!



In your case, I’d say you’re still at #1; you don’t need to do anything yet.

Starting to get slow? Then fix your algorithm. For example, why are you making three ajax requests? Make one.