УрокДебаг запросов к базе данных

В Drupal 7 все sql запросы собираются с помощью PDO конструкций, в которые передаются разнообразные параметры для построения запроса. И нередко приходится сталкиваться с ситуацией, когда хочется посмотреть результирующий sql запрос, сформированный в результате запуска PDO конструкции на исполнение. У нас есть как минимум три способа это сделать, каждый из них имеет свои плюсы и минусы. Давайте рассмотрим каждый из них.

Вывод запроса на экран средствами ядра

Предположим, у нас есть такой запрос:

$query = db_select('node', 'n');
$query->fields('n', array('nid', 'title'));
$query->condition('n.status', NODE_PUBLISHED);
$query->orderBy('n.nid');
$result = $query->execute();

Для того, чтобы вывести его на экран, достаточно у PDO объекта $query вызвать метод __toString():

drupal_set_message($query->__toString());

На экране мы получим такую строку:

debug_sql_1.png

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

Минус: не отображает значение плэйсхолдеров, подставленные в условия запроса.

Отображение sql запроса с помощью Devel'a

В модуле Devel есть поддержка такой замечательной функции, как dpq(). Посмотрите на пример её использования:

$query = db_select('node', 'n');
$query->fields('n', array('nid', 'title'));
$query->condition('n.status', NODE_PUBLISHED);
$query->orderBy('n.nid');
$result = $query->execute();
 
dpq($query);

Результат выполнения:

debug_sql_2.png

Плюс: запрос отображется так, как он будет отправлен в базу данных (кроме фигурных скобок вокруг таблицы).

Минусы:

  • Работает только для селектов (SelectQueryInterface).
  • Необходимо включение модуля Devel для работы функции. Однако учитывая, что дебаг на боевом сайте никто и не использует, особой проблемы это не должно вызывать.

Использование логирования ядра

В некоторых случаях нет возможности быстро отдебажить все sql запросы в рамках какой-либо функции. Для этого можно воспользоваться стандартным логированием ядра Друпала с выводом этой информации на экран. Вот как это работает на практике:

Database::startLog('node_load_debug');
$node = node_load(1);
dpm(Database::getLog('node_load_debug'));

В результате на экране я получу красивый вывод массива с помощью krumo, развернув который я увижу подробную информацию о каждом запросе. На скриншоте вы видите лишь первый запрос, у которого я открыл все параметры для просмотра:

debug_sql_3.png

Плюсы:

  • Достаточно мощный инструмент. Может использоваться как для вывода одиночных запросов, так и для вывода всех запросов от начала и до конца определённого периода.
  • Выводит все параметры запроса.
  • Показывает место вызова каждого запроса.
  • Отображение времени выполнения запроса.

Минусов пока не обнаружено.

Использование дебага в промышленных масштабах

Если вы используете дебаг запросов постоянно, вам может захотеться несколько оптимизировать этот процесс, а так же быстро управлять им. Примером такого управления может послужить использование метода addTag() в PDO конструкциях.

Добавляем в исходный запрос этот метод:

$query = db_select('node', 'n');
$query->fields('n', array('nid', 'title'));
$query->condition('n.status', NODE_PUBLISHED);
$query->orderBy('n.nid');
$query->addTag('debug');
$result = $query->execute();

Теперь, когда наш запрос помечен тэгом debug, мы можем отлавливать его с помощью hook_query_alter() или hook_query_TAG_alter() и выводить на экран:

/**
 * Implements hook_query_alter().
 */
function НАЗВАНИЕ_МОДУЛЯ_query_alter($query) {
  if ($query->hasTag('debug')) {
    dpq($query);
  }
}

В результате на экране отобразится запрос из второго метода, как и при использовании обычного dpq().

Явным плюсом такого подхода является лёгкое управление дебагом запросов. Например, перед отправкой кода на продакшн, вам достаточно закомментировать одну строку в модуле - и дебаг исчезнет. А при её раскомментировании, вы снова получите результат разбора всех PDO конструкций, помеченные тэгом debug.

P.S. Отдельную благодарность хотелось бы выразить Кате (kalabro), за поднятие этой темы и непосредственном участии в её создании.

Комментарии

Аватар пользователя kalabro
kalabro написала:

addTag('debug') особенно интересен для дебага EntityFieldQuery. Для меня это была единственная новая информация из статьи и комментариев How To Print SQL String Using Devel Module.

> Использование возможностей ядра + dpq()
dpq() там не нужен. Вместо dpm() можно использовать что угодно.

Про dpq() в минусах не сказано, что это только для селектов (SelectQueryInterface).

21.03.2013 09:13
Аватар пользователя Spleshka
Spleshka написал:

Спасибо за замечания, подправил статью.

23.03.2013 12:36
Аватар пользователя kalabro
kalabro написала:

kalabro написал:
Я написала! ;)

21.03.2013 09:15
Аватар пользователя drupby
drupby написал:

ты user ,а значит написал

22.03.2013 14:39
Аватар пользователя kalabro
kalabro написала:

на самом деле на кафешках и конфах были прецеденты, когда мне говорили, что видели меня в блоге Drupalace, только тогда я была пацаном :)

22.03.2013 21:14
Аватар пользователя Spleshka
Spleshka написал:

Сделал для тебя исключение :)

23.03.2013 12:31
Аватар пользователя andypost@drupal.org
andypost@drupal.org написал:

Кстати, для отладки в ядре есть нативная функция debug()

24.03.2013 18:49
Аватар пользователя Дмитрий
Дмитрий написал:

Если в файл devel/devel.module добавить строку $export = preg_replace('/[{}]/', '', $export); То одним минусом, связанным с фигурными скобками в выводе запроса, станет меньше.

22.11.2016 07:00
Аватар пользователя Дмитрий
Дмитрий написал:

UPD. Строка добавляется в метод dpm()

22.11.2016 07:02

Комментировать