Оптимизация работы MySQL: кеширование запросов

  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: SELECT data, created, headers, expire, serialized FROM cache_filter WHERE cid = '2:2056c4e5ca9610ab1a4da53e661676b3' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 27.
  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: UPDATE cache_filter SET data = '<p class=\"rtecenter\"><img alt=\"MySQL логотип\" width=\"140\" height=\"102\" src=\"http://muff.kiev.ua/files/mysql-logo.jpg\" /></p>\n<p class=\"rtejustify\">Занимаясь переносом хостинга, немало налопатил информации о СУБД MySQL. Заодно решил немного оптимизировать ее работу, включив поддержку кеширования.</p>\n<p class=\"rtejustify\">После установки MySQL уже поддерживает механизм кеширования запросов,&nbsp;однако по умолчанию он выключен. Параметры по умолчанию следующие:</p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"1\" width=\"100%\">\n<tbody>\n<tr>\n<td>\n<pre class=\"rtejustify\">\nmysql&gt; <strong>show variables like \'query%\';\n</strong>+------------------------------+---------+\n| Variable_name | Value |\n+------------------------------+---------+\n| query_alloc_block_size | 8192 |\n| query_cache_limit | 1048576 |\n| query_cache_min_res_unit | 4096 |\n| query_cache_size | 0 |\n| query_cache_type | ON |\n| query_cache_wlock_invalidate | OFF |\n| query_prealloc_size | 8192 |\n+------------------------------+---------+\n7 rows in set (0.00 sec)</pre></td>\n</tr>\n</tbody>\n</table>\n<p class=\"rtejustify\">Размер кеша равен нулю. Для того, чтобы задать кеш размером 32 МБ, необходимо добавить следующую строку в <em><strong>my.conf</strong></em> (в секцию [mysqld]):</p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"1\" width=\"100%\">\n<tbody>\n<tr>\n<td class=\"rtejustify\">query_cache_size = 32M</td>\n</tr>\n</tbody>\n</table>\n<p class=\"rtejustify\">Чтобы не перезапускать MySQL-сервер,&nbsp;изменим также и текущую конфигурацию, выполнив следующий запрос с правами суперпользователя:</p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"1\" width=\"100%\">\n<tbody>\n<tr>\n<td class=\"rtejustify\">mysql&gt; <strong>set <span class=\"spamspan\"><span class=\"u\">@</span> [at] <span class=\"d\">global [dot] query</span></span>_cache_size=32*1024*1024;</strong><br />\n Query OK, 0 rows affected (0.00 sec)</td>\n</tr>\n</tbody>\n</table>\n<p class=\"rtejustify\">Еще один параметр,&nbsp;на который следует обратить внимание - это <em><strong>query_cache_limit </strong></em>- он задает максимальный объем результата выполнения запроса, который может быть помещен в кэш.</p>\n<p class=\"rtejustify\">Проверить состояние кеша можно следующим запросом:</p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"1\" width=\"100%\">\n<tbody>\n<tr>\n<td class=\"rtejustify\">\n<pre class=\"rtejustify\">\nmysql&gt; <strong>show global status like \'Qcache%\';\n</strong>+-------------------------+----------+\n| Variable_name | Value |\n+-------------------------+----------+\n| Qcache_free_blocks | 21 |\n| Qcache_free_memory | 30943456 |\n| Qcache_hits | 3659 |\n| Qcache_inserts | 2409 |\n| Qcache_lowmem_prunes | 0 |\n| Qcache_not_cached | 75 |\n| Qcache_queries_in_cache | 841 |\n| Qcache_total_blocks | 1863 |\n+-------------------------+----------+\n8 rows in set (0.00 sec)</pre></td>\n</tr>\n</tbody>\n</table>\n<p class=\"rtejustify\">Значение параметров:</p>\n<ul>\n<li class=\"rtejustify\"><em><strong>Qcache_free_memory </strong></em>- объем свободной памяти, отведенной под кэш.</li>\n<li class=\"rtejustify\"><em><strong>Qcache_hits</strong></em> - количество запросов, отработанных из кэша.</li>\n<li class=\"rtejustify\"><em><strong>Qcache_inserts</strong></em> - количество вставок запросов в кэш.</li>\n<li class=\"rtejustify\"><em><strong>Qcache_lowmem_prunes</strong></em> - количество высвобождений памяти из-за наполненности кэша.</li>\n<li class=\"rtejustify\"><em><strong>Qcache_not_cached</strong></em> - количество запросов, не подлежащих кэшированию.</li>\n<li class=\"rtejustify\"><em><strong>Qcache_queries_in_cache</strong></em> - количество запросов, находящихся в кэше в настоящее время.</li>\n</ul>\n<p class=\"rtejustify\">Рассчитать эфективность кеширования можно по следующей формуле: <em><strong>Qcache_hits / (Qcache_inserts + Qcache_not_cached)</strong></em>.</p>\n<p class=\"rtejustify\">Собственно пора задаться вопросом,&nbsp;как именно работает кеш. Все очень просто. При каждом запросе типа SELECT вычисляется хэш-сумма строки запроса и ищется в кэше. Если находится - возвращается рузельтат из кэша, если нет - выполняется запрос, а результат заносится в кэш (при условии, что&nbsp;результат не больше значения <em><strong>query_cache_limit</strong></em>).<br />\nПри каждом запросе типа UPDATE, REPLACE, INSERT, DELETE, TRUNCATE или ALTER, удаляются из кэша все запросы, использующие таблицу, подвергшуюся обновлению.</p>\n<p class=\"rtejustify\">Стоит также отметить некоторые особенности кеширования,&nbsp;а именно:</p>\n<ul>\n<li class=\"rtejustify\">Различие запросов определяется буквально, сравнение чувствительно к реестру. Поэтому <em><strong>SELECT * FROM news</strong></em> и <em><strong>select * FROM news </strong></em>будут для кэша двумя разными запросами.</li>\n<li class=\"rtejustify\">В кэш всегда попадает результат выполнения запроса целиком, результаты выполнения подзапросов не кэшируются.</li>\n<li class=\"rtejustify\">Кэш работает одинаково для запросов к таблицам с различными механизмами хранения.</li>\n<li class=\"rtejustify\">Ряд запросов не подлежит кэшированию:\n<ul>\n<li class=\"rtejustify\">Запросы, содержащие одну из недетерминированных функций: <em><strong>NOW()</strong></em>, <em><strong>SLEEP()</strong></em>, <em><strong>RAND()</strong></em>, <em><strong>CURTIME()</strong></em>, <em><strong>LAST_INSERT_ID()</strong></em> и.др.</li>\n<li class=\"rtejustify\">Запросы, использующие функции или хранимые процедуры, определенные пользователем.</li>\n<li class=\"rtejustify\">Запросы, использующие значения локальных переменных.</li>\n<li class=\"rtejustify\">Запросы, обращающиеся к базам данных <em><strong>mysql </strong></em>или <em><strong>INFORMATION_SCHEMA</strong></em>.</li>\n<li class=\"rtejustify\">Запросы типа <em><strong>SELECT ... FOR UPDATE, SELECT ... IN SHARE MODE</strong></em>, <em><strong>SELECT ... INTO OUTFILE</strong></em>, <em><strong>SELECT ... INTO DUMPFILE</strong></em>, <em><strong>SELECT * FROM ... WHERE autoincrement_col IS NULL</strong></em>.</li>\n<li class=\"rtejustify\">Запросы, использующие временные таблицы.</li>\n<li class=\"rtejustify\">Запросы, не обращающиеся к таблицам.</li>\n<li class=\"rtejustify\">Запросы, которые генерируют предупреждения (warnings).</li>\n<li class=\"rtejustify\">В случае, если пользователь имеет права не на всю таблицу, а только на определенные колонки таблицы. Это исключение &mdash; следствие того, что кэш запросов один для всех пользователей, а права доступа средствами кэша проверяются лишь на уровне таблиц.</li>\n</ul>\n</li>\n</ul>\n<p class=\"rtejustify\">Если необходимо,&nbsp;чтобы запрос не попадал в кеш, используется директива <em><strong>SQL_NO_CACHE</strong></em>, которая размещается сразу после оператора <em><strong>SELECT</strong></em>.&nbsp; Пример выполнения такого запроса:</p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"1\" width=\"100%\">\n<tbody>\n<tr>\n<td>mysql&gt;&nbsp;SELECT SQL_NO_CACHE username&nbsp;FROM mail_users;</td>\n</tr>\n</tbody>\n</table>\n<p class=\"rtejustify\">&nbsp;</p>\n', created = 1767400889, expire = 1767487289, headers = '', serialized = 0 WHERE cid = '2:2056c4e5ca9610ab1a4da53e661676b3' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 112.
  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: SELECT data, created, headers, expire, serialized FROM cache_filter WHERE cid = '2:07243fc0252056071eaa62af8c18d662' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 27.
  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: UPDATE cache_filter SET data = '<p class=\"rtecenter\"><a class=\"thickbox\" href=\"/files/imagepicker/1/wake_up_ua.png\"><img alt=\"Вставай, Україно!\" class=\"imgp_img\" src=\"/files/imagepicker/1/thumbs/wake_up_ua.png\" style=\"height:200px; width:150px\" /></a></p>\n', created = 1767400889, expire = 1767487289, headers = '', serialized = 0 WHERE cid = '2:07243fc0252056071eaa62af8c18d662' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 112.
  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: SELECT data, created, headers, expire, serialized FROM cache_filter WHERE cid = '3:cc913d232116f0426090404133377d88' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 27.
  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: SELECT data, created, headers, expire, serialized FROM cache_filter WHERE cid = '2:d9a86123bfcbc57878743027b584400b' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 27.
  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: UPDATE cache_filter SET data = '<p class=\"rtecenter\"><a href=\"http://muff.kiev.ua/rss.xml\"><img alt=\"RSS\" width=\"160\" height=\"60\" src=\"http://muff.kiev.ua/files/muf-rss.png\" /></a></p>\n', created = 1767400889, expire = 1767487289, headers = '', serialized = 0 WHERE cid = '2:d9a86123bfcbc57878743027b584400b' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 112.
  • user warning: Table './muffsql1/cache_filter' is marked as crashed and should be repaired query: SELECT data, created, headers, expire, serialized FROM cache_filter WHERE cid = '3:39649256b636e3d5ded656bc52bd8c01' in /usr/local/www/muff.kiev.ua/includes/cache.inc on line 27.
Версия для печатиОтправить другуPDF version

MySQL логотип

Занимаясь переносом хостинга, немало налопатил информации о СУБД MySQL. Заодно решил немного оптимизировать ее работу, включив поддержку кеширования.

После установки MySQL уже поддерживает механизм кеширования запросов, однако по умолчанию он выключен. Параметры по умолчанию следующие:

mysql> show variables like 'query%';
+------------------------------+---------+
| Variable_name                |  Value  |
+------------------------------+---------+
| query_alloc_block_size       | 8192    |
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 0       |
| query_cache_type             | ON      |
| query_cache_wlock_invalidate | OFF     |
| query_prealloc_size          | 8192    |
+------------------------------+---------+
7 rows in set (0.00 sec)

Размер кеша равен нулю. Для того, чтобы задать кеш размером 32 МБ, необходимо добавить следующую строку в my.conf (в секцию [mysqld]):

query_cache_size = 32M

Чтобы не перезапускать MySQL-сервер, изменим также и текущую конфигурацию, выполнив следующий запрос с правами суперпользователя:

mysql> set @ [at] global [dot] query_cache_size=32*1024*1024;
Query OK, 0 rows affected (0.00 sec)

Еще один параметр, на который следует обратить внимание - это query_cache_limit - он задает максимальный объем результата выполнения запроса, который может быть помещен в кэш.

Проверить состояние кеша можно следующим запросом:

mysql> show global status like 'Qcache%';
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 21       |
| Qcache_free_memory      | 30943456 |
| Qcache_hits             | 3659     |
| Qcache_inserts          | 2409     |
| Qcache_lowmem_prunes    | 0        |
| Qcache_not_cached       | 75       |
| Qcache_queries_in_cache | 841      |
| Qcache_total_blocks     | 1863     |
+-------------------------+----------+
8 rows in set (0.00 sec)

Значение параметров:

  • Qcache_free_memory - объем свободной памяти, отведенной под кэш.
  • Qcache_hits - количество запросов, отработанных из кэша.
  • Qcache_inserts - количество вставок запросов в кэш.
  • Qcache_lowmem_prunes - количество высвобождений памяти из-за наполненности кэша.
  • Qcache_not_cached - количество запросов, не подлежащих кэшированию.
  • Qcache_queries_in_cache - количество запросов, находящихся в кэше в настоящее время.

Рассчитать эфективность кеширования можно по следующей формуле: Qcache_hits / (Qcache_inserts + Qcache_not_cached).

Собственно пора задаться вопросом, как именно работает кеш. Все очень просто. При каждом запросе типа SELECT вычисляется хэш-сумма строки запроса и ищется в кэше. Если находится - возвращается рузельтат из кэша, если нет - выполняется запрос, а результат заносится в кэш (при условии, что результат не больше значения query_cache_limit).
При каждом запросе типа UPDATE, REPLACE, INSERT, DELETE, TRUNCATE или ALTER, удаляются из кэша все запросы, использующие таблицу, подвергшуюся обновлению.

Стоит также отметить некоторые особенности кеширования, а именно:

  • Различие запросов определяется буквально, сравнение чувствительно к реестру. Поэтому SELECT * FROM news и select * FROM news будут для кэша двумя разными запросами.
  • В кэш всегда попадает результат выполнения запроса целиком, результаты выполнения подзапросов не кэшируются.
  • Кэш работает одинаково для запросов к таблицам с различными механизмами хранения.
  • Ряд запросов не подлежит кэшированию:
    • Запросы, содержащие одну из недетерминированных функций: NOW(), SLEEP(), RAND(), CURTIME(), LAST_INSERT_ID() и.др.
    • Запросы, использующие функции или хранимые процедуры, определенные пользователем.
    • Запросы, использующие значения локальных переменных.
    • Запросы, обращающиеся к базам данных mysql или INFORMATION_SCHEMA.
    • Запросы типа SELECT ... FOR UPDATE, SELECT ... IN SHARE MODE, SELECT ... INTO OUTFILE, SELECT ... INTO DUMPFILE, SELECT * FROM ... WHERE autoincrement_col IS NULL.
    • Запросы, использующие временные таблицы.
    • Запросы, не обращающиеся к таблицам.
    • Запросы, которые генерируют предупреждения (warnings).
    • В случае, если пользователь имеет права не на всю таблицу, а только на определенные колонки таблицы. Это исключение — следствие того, что кэш запросов один для всех пользователей, а права доступа средствами кэша проверяются лишь на уровне таблиц.

Если необходимо, чтобы запрос не попадал в кеш, используется директива SQL_NO_CACHE, которая размещается сразу после оператора SELECT.  Пример выполнения такого запроса:

mysql> SELECT SQL_NO_CACHE username FROM mail_users;

 

Ваша оценка: Нет Средняя: 4.1 (8 голосов)

Вставай, Україно!

Литература

Нoвая сенсация: Чукoтские хакеры взлoмали счеты.