Кэширование схем в Yii

Включив кэширование в приложении Yii я ожидал увидеть уменьшение количества запросов в БД. Нет, не получилось. Нужно настраивать кэш перед каждым запросом в базу данных.

Вот так указывается, что результат следующего простого запроса SQL должен быть помещён в кэш на 300 секунд.

<?php
$cmd = Yii::app()->db->cache(300)->createCommand("SELECT * FROM albums LIMIT 0, 30");
$albums = $cmd->queryAll();

Аналогично при использовании механизма Active Record:

<?php
$albums = Albums::model()->cache(300)->limit(30)->queryAll();

Подробнее об этом в официальной документации Yii framework.

Но если посмотреть в отладочные протоколы, то видно, что перед запросом через Active Record делается запрос на получение структуры таблицы.

SHOW FULL COLUMNS FROM `albums`
SHOW CREATE TABLE `albums`

И хотя инструкция по улучшению производительности рекомендует не пользоваться Active Record, от этих запросов можно избавиться. Нужно включить кэширование схем данных.

Как избавиться от запросов SHOW CREATE TABLE

Для включения кэширования схем данных нужно в настройках приложения указать время хранения схемы

    'db'=> array(
        // ... настройки подключения

        // Enabling Table Schema Caching (Disable SHOW CREATE TABLE) / Кеширование схем данных
        'schemaCachingDuration' => 3600,
    ),

Теперь описания таблиц, обращение к которым выполняется через Active Record, будет храниться в кэше один час.

Обновление кэша схем при изменении таблиц

При изменении таблиц нужно удалить старые описания схем из кэша. Самый простой способ: очистка всего кэша.

<?php
// Clear all cache / Очистить весь кэш
Yii::app()->cache->flush();

Но это очень непроизводительно, потому что из кэша удалятся вообще все данные.

Лучше удалить из кэша схему одной таблицы отдельной командой

<?php
// Clear or Refresh Table Schema Cache For One Table / Очистка из кэша схемы одной таблицы
Yii::app()->db->schema->getTable('albums', true);

Если нужно удалить описания всех известных таблиц, то есть встроенный механизм обновления, который удаляет описания всех известных таблиц, а для этого их сначала нужно загрузить из базы данных.

<?php
// Clear or Refresh All Table Schema Cache / Удаление из кэша схем всех таблиц

// Load all tables of the application in the schema / Загрузить описание всех таблиц
Yii::app()->db->schema->getTables();

// Сlear the cache of all loaded tables / Удаление из кэша описаний всех загруженных таблиц
Yii::app()->db->schema->refresh();

При использовании механизма миграций есть возможность очистить кэш схемы одной таблицы

<?php
/**
 * Пример файла миграции, изменяющего таблицу albums
 */
class m140318_185558_albums_artist extends CDbMigration
{
    public function up()
    {
        $this->addColumn('albums', 'artist', 'VARCHAR(255) DEFAULT NULL COMMENT \'Имя исполнителя\'');
        // ... другие команды

        // Refresh table schema cache for one table / Обновление в кэше описания схемы одной таблицы
        $this->refreshTableSchema('albums');
    }
}

Если нужно очистить информацию о всех схемах, можно воспользоваться вот таким классом DbMigration

<?php
/**
 * /protected/components/DbMigration
 */

/**
 * Class DbMigration
 *
 * Класс компоненты миграций, расширяющий работу с кэшем описаний схем всех таблиц
 */
class DbMigration extends CDbMigration
{
    /**
     * Refresh all tables schemas cache / Обновление в кэше описаний схем всех таблиц
     */
    public function refreshTableSchemas()
    {
        echo "    > refresh all tables schemas cache ...";
        $time=microtime(true);
        Yii::app()->db->schema->getTables(); // load all tables
        Yii::app()->db->schema->refresh(); // remove all loaded from cache
        Yii::app()->db->schema->getTables(); // load all tables again and store into cache
        echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n";
    }
}

Полезные ссылки:
* средство отладки приложений yii-debug-panel
* Улучшение производительности в приложениях на базе фреймворка Yii
* механизм миграций в Yii

Павел Волынцев

Уже более 15 лет занимаюсь разработкой веб-проектов. Fullstack Senior Developer. IT евангелист — доношу свет знаний об информационных технологиях. Профессиональные цели: Дать людям возможность дать людям больше.

Читайте также:

  • roman

    Спасиб, я и не знал что можно обновить закэшированную схему из миграций ( ну и вообще не знал что схема может обновить 🙂 )

  • alex

    'components' => [
    // ...
    'db' => [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=mydatabase',
    'username' => 'root',
    'password' => '',
    'enableSchemaCache' => true,

    // Duration of schema cache.
    // 'schemaCacheDuration' => 3600,

    // Name of the cache component used. Default is 'cache'.
    //'schemaCache' => 'cache',
    ],
    'cache' => [
    'class' => 'yii\caching\FileCache',
    ],

    • pvolyntsev

      Да, так указывается время хранения схемы. Но представь, что при миграции изменилась структура таблицы, например, удалено ненужное поле. Если ждать целый час, пока обновится кэш, то будет много ошибок. Лучше кэш структуры таблицы удалить.

  • ret

    Yii::app()->cache->flush();

    в какой файл прописать надо , я как раз структуру БД поменял вот и ввыводит ошибку , новичок в Yii

    • Написать команду Yii::app()->cache->flush(); можно где угодно, в любом файле. Эта конструкция носит общесистемный характер.

      Я хотел отметить, что схему надо чистить в файлах миграциии. Посмотри на класс

      class m140318_185558_albums_artist extends CDbMigration { }

      Там после изменения таблицы нужно обновить данные о схеме этой таблицы albums с помощью

      $this->refreshTableSchema(‘albums’);

  • Yii::app()->cache->flush() можно вставить где угодно говоришь? Я вставляю — не работает! Но я только изучаю этот фреймфорк. Подключился к базе через ActiveRecord. Видимо запрос к базе где-то кэшируется, т.к. в ActiveRecord ставлю limit или добавляю where, в браузере ничего не меняется.

    • Нет, я был неправ. Эта команда сильно зависит от используемой системы кэширования и не всегда можно сделать flush программно из Yii. Знаю, что это работает для Redis, но для memcached или файлов приходится флушить другими способами

      Если кэш файловый — удалять директорию с файлами
      Если это memcached — делать команду `sudo service memcached restart`

    • Не могу дать ответ на твой вопрос без тестового примера кода. Опубликуй его gist или ещё где-нибудь и скажи, какая условно функция или строка кода тебя беспокоит, как должна работать.