<rmcreative>

RSS

Кеширование SQL-запросов в Yii

11 февраля 2011

Сегодня Qiang реализовал ещё одну интересную штуку для Yii: кеширование запросов к базе данных на всех уровнях от DAO до ActiveRecord.

$sql = 'SELECT * FROM tbl_post LIMIT 20';
// кешируем результат запроса 1000 секунд
$rows = Yii::app()->db->cache(1000)->createCommand($sql)->queryAll();

Если данные в таблице меняются, можно попробовать инвалидировать кеш, используя менее затратный запрос:

$sql = 'SELECT * FROM tbl_post LIMIT 20';
// сбрасываем кеш, если результат изменился
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
// кешируем на 1000 секунд
$rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll();

С AR это работает так:

$posts = Post::model()->cache(1000)->findAll();
$posts = Post::model()->cache(1000)->with('author')->findAll();

Опробовать можно, забрав код из SVN. Войдёт в релиз 1.1.7.

Комментарии RSS

  1. №3894
    Ncs
    Ncs 11.02.2011, 21:28:46

    А sql в CActiveDataProvider как закэшировать?

  2. №3896
    Ekstazi
    Ekstazi 11.02.2011, 22:06:27

    Уау, я тока хотел писать костыль для этого ) Ребята, вы лучшие. doctrina уже отдыхает. :)

  3. №3898
    Sam
    Sam 11.02.2011, 23:32:23

    Ncs,

    $dataProvider = new CActiveDataProvider(Post::model()->cache(1000));
  4. №3902
    Ekstazi
    Ekstazi 12.02.2011, 11:33:40

    Sam, а ты не знаешь как закэшировать запрос так чтоб он был в кэше только для этой страницы ? К примеру в примеру про RBAC :

    class WebUser extends CWebUser {
    // private $_model;
    public function getRole(){
    return $this->getModel()->role;
    }
     
    protected function getModel(){
    return User::model()->cache(<какие параметры тут передать, чтоб кеш был действителен только для текущего http запроса>)
    }->findByPk($this->id);
    }

    Тем самым хочу избавиться от: private $_model;

  5. №3904
    Sam
    Sam 12.02.2011, 20:26:49

    По-моему, private $_model в этом случае логичней.

  6. №3906
    Ekstazi
    Ekstazi 12.02.2011, 21:21:19

    В этом - да, но, есть и другие. Так что вопрос все еще актуален. Сталкивался пару раз с подобной задачей, но, пример не припомню уже.

  7. №3907
    Павел
    Павел 12.02.2011, 23:14:58

    Т.е., при соответствующем конфиге, конструкция

    $posts = Post::model()->cache(1000)->findAll();

    будет использовать memcached? проверка на наличие кеша будет автоматом делаться? просто из гайда не очень понятно.

  8. №3908
    Sam
    Sam 12.02.2011, 23:39:04

    Павел, да и да.

    Ekstazi, я бы решил, передав в cache вторым параметром что-то вроде CGlobalStateCacheDependency или CExpressionDependency.

  9. №4394
    тимоха
    тимоха 15.04.2011, 16:14:28

    Все это замечательно. но почему в логах при выполнении данного кода :

    $dataProvider = new CActiveDataProvider(Post::model()->cache(1000));

    нет записи, что данные по запросу берутся из кэша, как например такое :

    15:56:52.822227     trace   system.db.CDbCommand    
     
    Querying SQL: SELECT * FROM "users" "t" WHERE "t"."id"=1 LIMIT 1
     
    15:56:52.822323     trace   system.db.CDbCommand    
     
    Querying SQL: SELECT value FROM YiiCache WHERE
    id='603b348a2ec340b5e1fc66def15b9f88' AND (expire=0 OR expire>1302868612)
     
    15:56:52.823719     trace   system.caching.CDbCache     
     
    Serving
    "yii:dbquerypgsql:host=192.168.203.121;port=5432;dbname=ravpn:postgres:SELECT
    * FROM "users" "t" WHERE "t"."id"=1 LIMIT 1:a:0:{}" from cache
     
    15:56:52.823744     trace   system.db.CDbCommand    
     
    Query result found in cache

    вместо такого, выдается обычный запрос типа :

    6:12:58.463514  trace   system.db.ar.CActiveRecord  
     
    Company.findAll()
     
    16:12:58.463680     trace   system.db.CDbCommand    
     
    Querying SQL: SELECT * FROM "company" "t" WHERE t.is_deleted=false ORDER BY
    active_users_count desc LIMIT 10
     
    16:12:58.471292     trace   system.CModule  
     
    Loading "assetManager" application component

    такое чувство, что запрос не кэшируется совсем никак.

  10. №5743
    Роман
    Роман 08.01.2012, 14:37:34

    а есть такая штука, чтобы в ходе выполнения приложения (допустим там одни селекты) запрос выполнившись один раз, больше не выполнялся, а его данные брались бы из временного кэша? А то SHOW CREATE TABLE выполняется каждый раз при инициализации модели например

  11. №5744
    Sam
    Sam 09.01.2012, 11:01:00

    Есть. В руководстве описано.

  12. №7044
    Jukka
    Jukka 13.11.2012, 14:38:06

    А в CSqlDataProvider есть cache?

  13. №7045
    Jukka
    Jukka 13.11.2012, 14:43:38

    Видимо так new CSqlDataProvider($sql, array('params'=>$params, 'db'=>Yii::app()->db->cache(1000))); ?

  14. №7725
    Hell
    Hell 21.03.2013, 15:50:42

    А можно закешировать само соединение? например : $connect = new CDbConnection('mysql:host=localhost;dbname=test','root','root'); У меня почему то не получается

  15. №7732
    Sam
    Sam 22.03.2013, 23:23:38

    В каком смысле закешировать соединение?

  16. №9018
    Alex
    Alex 20.05.2014, 17:35:04

    А почему при кэшировании запроса с параметрами вылетает ошибка ? Пример:

    $sql = 'SELECT * FROM {{city}} WHERE geo_id = :geoid';
    $d = new CDbCacheDependency($sql);
    $res = Yii::app()->db->cache(1000, $d)->createCommand($sql)->queryRow(true, array(':geoid' => $id));

    Без кэширования все работает прекрасно, с кешем имеем ошибку:

    CDbCommand не удалось исполнить SQL-запрос: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound. The SQL statement executed was: SELECT * FROM city WHERE geo_id = :geoid. The SQL statement executed was: SELECT * FROM city WHERE geo_id = :geoid. Bound with :geoid=1526384

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.