SqlMon: плагин для анализа SQL-запросов
Поиск слабых мест производительности: анализируем SQL-запросы
Меня всегда интересовало, насколько эффективно WordPress работает с базой данных, и насколько хорошо спроектирована база данных.
Практически в каждом проекте, над которым я работаю, я использую те или иные средства для анализа производительности скрипта и поиска его слабых мест. Для разработчиков не является секретом, что во многих случаях плохая производительность работы скрипта обусловлена низкой производительностью SQL-запросов. И, как правило, низкое быстродействие запросов связано с их неоптимальностью (что включает в себя отсутствие необходимых индексов в базе данных).
Однажды столкнувшись с ужасной производительностью WordPress и не имея возможности анализировать код десятка поставленных плагинов, я стал решать задачу иначе, в результате чего родился плагин для анализа SQL-запросов.
Принцип работы. Плагин устанавливает обработчики действий, которые позволяют перехватить запрос к базе данных непосредственно перед его выполнением. Если перехваченный запрос — SELECT, UPDATE или DELETE, то скрипт пытается его "объяснить" — выполнить EXPLAIN над запросом. Предвидя возражения, что EXPLAIN работает только с SELECT, но никак не с DELETE и UPDATE, поясняю: запросы DELETE и UPDATE переписываются в SELECT, например:
FROM `t1`
INNER JOIN `t2`
ON `t1`.`id` = `t2`.`id`
WHERE `t2`.`key` = 'value'
LIMIT 5
будет переписан в
FROM `t1`
INNER JOIN `t2`
ON `t1`.`id` = `t2`.`id`
WHERE `t2`.`key` = 'value'
LIMIT 5
Возможно, переписывание работает не всегда, но такие случаи мне еще не встречались
Я предполагаю, что Вы понимаете, для чего нужен EXPLAIN и как следует понимать результаты, которые он выдаёт. Если это не так, то очень рекомендую прочитать статью "Optimizing Queries with EXPLAIN", а затем вернуться к данной статье.
Плагин в футере темы (кстати, это относится и к админке) выдаст подробный лог запросов с их объяснением. Это может выглядеть примерно так:
Установка. К сожалению, установка данного плагина полностью не автоматизируется: кое-что надо делать вручную. После активации плагина в WordPress нужно выполнить следующие действия:
- Добавить в файл
/wp-config.phpследующие строки:[-]View Code PHPПервая строка активирует режим перехвата и анализа запросов, вторая строка содержит массив с IP-адресами, которым разрешен просмотр лога запросов. Естественно, нужно указать свои адресаdefine('SQLMON_ENABLED', true);
$sqlmon_allowed_ips = array('70.87.222.86', '195.10.218.132', '127.0.0.1');
- Далее предстоит пропатчить один файлик WordPress:
/wp-includes/wp-db.php. Сразу объясню, зачем это нужно: WordPress не предоставляет нормальных возможностей отловить запрос до его выполнения. Фильтрqueryдля наших целей не подходит: во-первых, последующий плагин может переписать запрос, во-вторых, я уже насмотрелся на плагины, которые лезут переписывать запрос, если видят SELECT. Проверено, что переписывание EXPLAIN SELECT такими плагинами приводит к синтаксической ошибке.Теперь о том, что нужно менять. В файле
/wp-includes/wp-db.phpесть класс wpdb, в котором есть метод query. В этом методе нужно найти строки[-]View Code PHP// Perform the query via std mysql_query function..
if (SAVEQUERIES)
$this->timer_start();
$this->result = @mysql_query($query, $this->dbh);
++$this->num_queries;и изменить их:
[-]View Code PHP// Perform the query via std mysql_query function..
if (SAVEQUERIES)
$this->timer_start();
if (true == function_exists('do_action')) {
do_action('before_query', $query, $this->dbh);
}
$this->result = @mysql_query($query, $this->dbh);
if (true == function_exists('do_action')) {
do_action('after_query', $query, $this->dbh);
}
++$this->num_queries;Для тех, кто предпочитает иметь дело с патчами, привожу патч в формате unified diff (внимание: патч проверялся только на WordPress 2.5.1):
[-]Download wp-db-2.5.1.php.diff--- wp-db.old.php 2008-03-21 01:34:32.000000000 +0200
+++ wp-db.php 2008-06-13 03:02:27.000000000 +0300
@@ -272,7 +272,16 @@
if (SAVEQUERIES)
$this->timer_start();
+ if (true == function_exists('do_action')) {
+ do_action('before_query', $query, $this->dbh);
+ }
+
$this->result = @mysql_query($query, $this->dbh);
+
+ if (true == function_exists('do_action')) {
+ do_action('after_query', $query, $this->dbh);
+ }
+
++$this->num_queries;
if (SAVEQUERIES)
После этого перезагружаем страницу и смотрим
Update: для WordPress 2.6 патч будет выглядеть следующим образом:
+++ wp-db.php 2008-08-03 10:39:14.000000000 +0300
@@ -605,7 +605,16 @@
if ( defined('SAVEQUERIES') && SAVEQUERIES )
$this->timer_start();
+ if (true == function_exists('do_action')) {
+ do_action('before_query', $query, $this->dbh);
+ }
+
$this->result = @mysql_query($query, $this->dbh);
+
+ if (true == function_exists('do_action')) {
+ do_action('after_query', $query, $this->dbh);
+ }
+
++$this->num_queries;
if ( defined('SAVEQUERIES') && SAVEQUERIES )



[...] “13 Тэгов, которые следует удалить из вашей темы” SqlMon: плагин для анализа SQL-запросов » Июнь 12, [...]
[...] был получен при помощи плагина SQL Monitor (в целях повышения удобочитаемости, я изменил [...]
Для WordPress 2.6.1 можно использовать тот же самый патч, что и для WordPress 2.6.