Статья для новичков. В MySQL есть встроенное кэширование запросов. Подробнее можно почитать на Хабре. Тут я скажу о главном плюсе и главном минусе такого кэширования и приведу пример своего сервака.
Плюсы
Во-первых, кэширование запросов существенно ускоряет генерацию страницы. Существенно потому, что SQL-запросы почти всегда являются главным тормозом.
Во-вторых, встроенное кэширование гораздо проще в реализации, чем кэширование на уровне приложения.
Указав в конфиге "query_cache_type=1" мы включаем кэширование всех запросов. При этом нам не нужно запариваться с инвалидацией кэша — база сама знает когда таблица изменилась и кэш сбрасывается автоматически. Приведу пример.
// это кэширование с помощью MySQL // тут даже менять в коде ничего не нужно (делаем запрос как обычно) $tags = $DB->select('SELECT * FROM tags'); // а вот то же самое кэширование на файлах $filemtime = filemtime($_SERVER['DOCUMENT_ROOT'].'/cache/tags.txt'); if ((time() - $filemtime) > 60*60*24) { $tags = $DB->select('SELECT * FROM tags'); $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/cache/tags.txt', 'w'); flock($fp, LOCK_EX); fwrite($fp, serialize($tags)); flock($fp, LOCK_UN); fclose($fp); } else { $tags = unserialize(file_get_contents($_SERVER['DOCUMENT_ROOT'].'/cache/tags.txt')); } // причем при добавлении/изменении тегов, // нам нужно дописать код по инвалидации кэша. if ($tag_change) { $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/cache/tags.txt','a'); ftruncate($fp, 0); }
Если вместо файлов мы используем какой-то другой вид кэширования на уровне приложения, например Memcache, то это ничего не меняет — нам всё равно нужно бегать по всему коду и вставлять if-else.
Короче говоря, самый большой плюс кэширования MySQL — прописал одну сточку в конфиге query_cache_type=1 и тут же нагрузка на базу упала. Даже код не нужно трогать.
Минусы
Самый большой минус в том, что инвалидация кэша происходит по слишком простому алгоритму: база смотрит изменилась ли таблица, из которой мы хотим сделать запрос. На примере это выглядит так. Есть 100 000 пользователей, которых мы закэшировали. Пришел пользователь и поменял что-то в профиле. Казалось бы, можно сбросить 1 кэш (только для того пользователя, который что-то изменил). Но MySQL сбрасывает весь кэш пользователей, потому что он не знает у какого пользователя изменилась информация — он видит только дату изменения таблицы.
Таким образом, мы очень быстро забьем оперативную память, которой у нас и так мало, а кэширование будет малоэффективным.
Но если у вас данные меняются редко, то кэш MySQL — хорошее решение. Правда, если на серваке работает несколько сайтов, то кэширование включается для всех сразу. Поэтому, если памяти мало, то можно вручную указать какие запросы кэшировать, а какие нет. Делается это так
- Прописываем в конфиге query_cache_type=2
- В запросах, которые хотим закэшировать пишем директиву SQL_CACHE:
'SELECT SQL_CACHE * FROM tags'
Как видно, в этом случае нам всё-таки придется пробежаться по коду и понаставлять SQL_CACHE в запросы.
Многие таблицы (например, таблица городов, таблица категорий и другие справочники) не меняются годами, поэтому кэш там будет лежать вечно.
Многие сайты обновляются 2-3 раза в день, а кол-во просмотров переваливает за тысячи — в этом случае кэш тоже будет весьма эффективным.
Теперь смотрим статистику (это у меня за 5 дней)
Variable_name | Value |
---|---|
Qcache_free_blocks | 9 |
Qcache_free_memory | 12074192 |
Qcache_hits | 44614 |
Qcache_inserts | 1396 |
Qcache_lowmem_prunes | 0 |
Qcache_queries_in_cache | 1182 |
Qcache_total_blocks | 2388 |
Как видно, 96% запросов берется из кэша.
В довершение статьи мой конфиг
query_cache_type = 2 query_cache_limit = 1M query_cache_size = 16M
> Статья для новичков.
Мой гордость не позволила читать дальше:) Наверное хорошая статья, надеюсь не забыл упомянуть о случаях когда квери кеш лучше отключать
Здравствуйте! Спасибо за статью.
Подскажите, как вы определили - "Как видно, 96% запросов берется из кэша."???
У меня вот такие данные:
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 9 |
| Qcache_free_memory | 49016624 |
| Qcache_hits | 23509 |
| Qcache_inserts | 24011 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 863 |
| Qcache_queries_in_cache | 16557 |
| Qcache_total_blocks | 33157 |
+-------------------------+----------+
Как мне рассчитать эффективно или нет использование?
Настройка my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=****
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
key_buffer_size = 16M
key_cache_division_limit = 70
tmp_table_size = 16M
max_heap_table_size = 16M
query_cache_size = 64M
query_cache_type = 1
query_cache_limit = 2M
long_query_time = 0.5
slow_query_log_file = /var/log/mysql-slow.log
slow_query_log = 0
skip-innodb
thread_cache_size = 4
table_cache = 128
Qcache_hits 44614
Qcache_inserts 1396
(Qcache_inserts/Qcache_hits)*100%=3.1% даже так.
Qcache_inserts - происходит когда в кэше нет запроса или данные в кэше уже устарели, т.е. мы лезим в базу на диск, получаем данные и сохраняем в кэш.
Qcache_hits - когда запрос оказался в кэше и мы его взяли из памяти.
Чем меньше соотношение (Qcache_inserts/Qcache_hits) - тем лучше. Тем меньше данных берется с диска и тем больше данных берется из кэша.
В твоем случае эффективность 50%. При этом памяти хватает. Видимо ты меняешь данные в таблице и все кэши для этой таблицы сбрасываются.
Например, таблица постов post.
В кэше куча данных вида
select * from post where id=1
select * from post where id=2
select * from post where id=3
select * from post where id=n
Но как только ты вставил новый пост в базу или обновил у любого поста что-то, то сбрасываются все вышеперечисленные кэши.
Если это так, то нужно ставить индексы в базе - чтобы с диска быстрее читалось. Ну и переходить на более эффективный вид кэша типа Memcached http://ekimoff.ru/394/ - но здесь уже придется код править и думать над связями.
Кстати, у тебя long_query_time = 0.5 - не получится. mysql умеет только логировать запросы более 1 секунды. т.е этот параметр должен быть больше 1.