Блог сисадміна-початківця Виявлення поганих запитів у БД MySQL

Виявлення "поганих" запитів у БД MySQL

Основну частину ресурсів на веб-сервері (apache+nginx+php+mysql) використовує MySQL. Іноді буває так, що MySQL не вистачає з яких-небудь причин ресурсів, повністю забивається пам'ять, система йде в swap. У цьому винні довгі запити, які дуже сильно навантажують MySQL. Так сталося зі мною. Далі я розповім, як виявити проблему та як їй протистояти.

Існує зручна утиліта для системного моніторингу atop, за допомогою якої можна спостерігати системні ресурси.

# chmod +x mysql_processes # crontab -e */5 * * * * /root/mysql_processes

Серед запитів можна побачити дуже довгі, я наведу приклад середнього запиту з однієї бази: # cat /etc/mysql/processes.report 31/08/2014 12:30:01 Id User Host db Command Time State Info 329103 user localhost database Query 0 Sending data SELECT a.id, a.title, a.alias, a.title_alias, a.introtext, a.language, a.checked_out, a.che cked_out_time, a. catid, a.created, a.created_by, a.created_by_alias, CASE WHEN a.modified = 0 THEN a.created ELSE a.modified END як modified, a.modified_by, uam.name як modified_b y_name,CASE WHEN a.publish_up = 0 THEN a.created ELSE a.publish_up END як publish_up,a.publish_down, a.images, a.urls, a.attribs, a.metadata, a.metakey, a.metadesc, a.access, a.hi ts, a.xreference, a.featured, LENGTH(a.fulltext) AS readmore,CASE WHEN badcats.id не є null THEN 0 ELSE a.state END AS state,c.title AS category_title, c.path AS category_route, c. AS category_access, c.alias AS category_alias,CASE WHEN a.created_by_alias > ' ' THEN a.created_by_alias ELSE ua.name END AS author,ua.email AS author_email,(\nSELECT MA X(contact.id) AS id\nFROM tar_contact_detailsAS contact\nWHERE contact.published = 1 І contact.user_id = a.created_by) як contactid,parent.title як parent_title, parent.id як p parent_id, parent.path як parent_route, parent.alias як parent_alias,ROUND(v. rating_sum / v.rating_count, 0) AS rating, v.rating_count як rating_count,c.published, CASE WHEN badcat s.id дорівнює нулю THEN c.published ELSE 0 END AS parent_published\nFROM tar_content AS\nLEFT JOIN tar_content_frontpage AS fp ON fp.content_id = a.id\nLEFT JOIN tar_categories AS c ON c.id = a.catid\nLEFT JOIN tar_users AS ua ON ua.id = a.created_by\nLEFT JOIN tar_users AS uam ON uam.id = a.modified_by\ nLEFT JOIN tar_categories як батьківський ON parent.id = c.par ent_id\nLEFT JOIN tar_content_rating AS v ON a.id = v.content_id\nLEFT OUTER JOIN (ВИБЕРІТЬ cat.id як ідентифікатор FROM tar_categories AS cat JOIN tar_categories ЯК батьківський ON cat. lft МІЖ parent.lft ТА parent.rgt WHERE parent.extension = 'com_content' AND parent.published != 1 GROUP BY cat.id ) AS badcats ON badcats.id = c.id\nWHERE a.access IN (1) AND c.access IN (1) AND CASE WHEN badcats.id is null THEN a.state ELSE 0 END = 1 AND a.featured = 0 AND a.catid IN (85) AND (a.publish_up = '0000-00-00) 00:00:00' АБО a.publish_up = '2014-08-31 08:29:59')\nORDER BY a.created DESC LIMIT 0, 3 329104

Таким чином можна шукати проблемні бази, але це самий примітивний варіант. В Інтернеті є відмінний скрипт, який аналізує повільний журнал MySQL. Якщо цей лог не ведеться, то рекомендую його задати. # vim /etc/mysql/my.cnf . log_slow_queries = /var/log/mysql/mysql-slow.log

Так, качаємо скрипт і аналізуємо наш повільний журнал. # cd /tmp # wget http://www.maatkit.org/get/mk-query-digest # chmod +x mk-query-digest # ./mk-query -digest /var/log/mysql/mysql-slow.log

По виведенню роботи скриптаможна зробити собі висновки про проблемні бази та запити. Надалі потрібно або оптимізувати запити, або бази.