Главная > Программы > База данных > MySQL Кэширование запросов в MySQL17 августа 2008, 21:02
Автор: Григорий Рубцов [rgbeast]
Кэширование запросов позволяет повысить производительность приложений, не погружаясь в структуру самих запросов. Мы рассмотрим встроенный в MySQL механизм кэширования запросов и альтернативный подход для случаев, когда встроенный механизм неприменим. Встроенный механизм кэширования запросов в MySQL.MySQL содержит встроенный механизм кэширования запросов, который, однако не включен по умолчанию. Вот такие параметры выставленны по умолчанию в MySQL 5.0: mysql> show variables like 'query_cache%';
+------------------------------+---------+ | Variable_name | Value | +------------------------------+---------+ | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 0 | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | +------------------------------+---------+ Чтобы включить кэш запросов и выделить под него 32 мегабайта памяти можно выполнить запрос set @@global.query_cache_size=32*1024*1024; с правами суперпользователя, а чтобы сделать эту настройку постоянной, следует добавить в my.cnf в подраздел [mysqld] строчку query_cache_size=32M. Второй полезный параметр - query_cache_limit задает максимальный объем результата выполнения запроса, который может быть помещен в кэш После включения кэш работает автоматически:
Отметим следующие особенности работы кэша:
В качестве примера запроса, который может быть кэширован, приведем запрос, формирующий список обсуждений на главной странице webew.ru: SELECT t.*, (SELECT body FROM entities WHERE id=t.lastid) body
FROM (SELECT e2.type,e2.id,e2.title,e2.active, count(*)-IF(e2.type=3,1,0) cnt, MAX(e.id) lastid, MAX(e.created) lastcreated FROM entities e LEFT JOIN entities e2 ON e2.id=IF(e.foreparent,e.foreparent,e.id) WHERE e.active = 1 AND e2.active = 1 AND e.type=3 GROUP BY e2.id ORDER BY MAX(e.created) DESC LIMIT 10) t ORDER BY lastcreated DESC Запрос выполняет сортировку статей и тем по дате последнего комментария. Обращения к главной странице сайта происходят чаще, чем добавление комментариев или статей, поэтому кэш достаточно эффективен. Текущее состояние кэшаПосмотреть состояние кэша можно с помощью запроса: mysql> SHOW GLOBAL STATUS LIKE 'Qcache%';
+-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_free_blocks | 973 | | Qcache_free_memory | 14282000 | | Qcache_hits | 3293750 | | Qcache_inserts | 252819 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 66645 | | Qcache_queries_in_cache | 1342 | | Qcache_total_blocks | 3709 | +-------------------------+----------+ 8 rows in set (0.00 sec) Здесь:
Мерой эффективности кэша может служить отношение Qcache_hits / (Qcache_inserts + Qcache_not_cached). Как избежать использования кэша?В ряде случаев, желательно не использовать кэш. Наиболее распространены две ситуации:
Для выполнения запроса без использования кэша применяется директива SQL_NO_CACHE, которую помещают сразу после оператора SELECT. Например: SELECT SQL_NO_CACHE id,title,author FROM news where message like '%швабра%';
Альтернативные способы кэшированияНесмотря на то, что встроенный кэш запросов представляет мощный и ясный механизм, в ряде случаев он неприменим. Опишем наиболее распространенные:
Последняя причина достаточно распространена в рунете и обычно является ошибкой проектирования. Например, многие реализуют простой счетчик просмотров статьи (каюсь, и я так делал, но сейчас использую Бревно) в виде запроса UPDATE articles SET viewcount=viewcount+1 WHERE id=542. Данный запрос при каждом просмотре статьи обновляет счетчик и вместе с тем удаляет все кэшированные запросы к таблице articles. В ряде случаев, данная ошибка приводит к потере производительности в десятки раз. Для эффективного использования кэша следует выносить часто обновляемые поля в отдельную таблицу. Предположим, таблица часто обноваляется, но нам достаточно обновлять информацию на главной раз в минуту. Мы приведем простой способ ручного кэширования запроса с помощью MEMORY-таблицы. Если результат, хранящийся в MEMORY-таблице старше одной минуты, будем выполнять запрос и заносить результат в MEMORY-таблицу. Первое, проверим существует ли таблица с кэшированным результатом не старше одной минуты: SELECT (create_time > now() - INTERVAL 1 MINUTE)
fresh FROM cache_mainpage_query LIMIT 1;
Анализируем значение fresh в полученной строке. Если fresh=0 или произошла ошибка, значит запрос следует выполнить и внести в MEMORY-таблицу: DROP TABLE IF EXISTS 'cache_mainpage_query';
CREATE TABLE cache_mainpage_query ENGINE=MEMORY SELECT now() AS create_time, ... FROM ... WHERE ... ORDER BY ... LIMIT ...; Затем, как в случае c=0, так и в случае c=1, выполняем запрос и возвращаем результат клиенту: SELECT * FROM cache_mainpage_query ORDER BY ...;
Замечание. В рассмотренном примере время создания таблицы заносится в каждую строчку временной таблицы (колонка create_time). Это неэффективно по занимаемому месту в памяти, поэтому если объем памяти станет узким местом, следует перенести время кэширования в отдельную таблицу. Если правило сортировки сложное (например, требует подключения дополнительных таблиц или вычислений над полями), то сортировка кэшированного запроса займет время. Чтобы этого избежать, пронумеруем строки при выполнении основного запроса: SET @c:=0;
CREATE TABLE cache_mainpage_query ENGINE=MEMORY SELECT now() AS create_time, @c:=@c+1 AS ord, ... FROM ... WHERE ... ORDER BY ... LIMIT ...; Выборка в этом случае упрощается: SELECT * FROM cache_mainpage_query ORDER BY ord;
С MEMORY-таблицами связано одно ограничение: в таких таблицах нельзя хранить поля типа BLOB/TEXT. Если Вам требуется хранить поля такого типа, можно либо создать MEMORY-таблицу явно с полями типа varchar() длиной до 65535 символов, либо использовать таблицы типа MyISAM. Мы рассмотрели далеко не все варианты альтернативного кэширования, например, за кадром оказалось кэширование с помощью memcached и кэширование готовых кусков HTML. Напишите в комментариях, какие темы из области оптимизации производительности MySQL вам интересны. Статья написана по материалам онлайн-курса «Оптимизация производительности MySQL». © Все права на данную статью принадлежат порталу webew.ru. Перепечатка в интернет-изданиях разрешается только с указанием автора и прямой ссылки на оригинальную статью. Перепечатка в печатных изданиях допускается только с разрешения редакции. Главная > Программы > База данных > MySQL |