<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ars Longa, Vita Brevis &#187; SQLMon</title>
	<atom:link href="http://blog.sjinks.pro/tag/sqlmon/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.sjinks.pro</link>
	<description>Quod scripsi, scripsi</description>
	<lastBuildDate>Mon, 06 Feb 2012 17:56:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>SQLMon для Yii</title>
		<link>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/</link>
		<comments>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/#comments</comments>
		<pubDate>Tue, 22 Nov 2011 15:02:18 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQLMon]]></category>
		<category><![CDATA[лог]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=947</guid>
		<description><![CDATA[Расширение для анализа производительности SQL-запросов для Yii Одной из вещей, которых мне очень не хватало при разработке сайтов на Yii — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа. Ситуацию частично исправило расширение под названием Yii DB profiler. Но остались некоторые неудобства: Отображение запросов в порядке убывания времени выполнения — в принципе, это [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Расширение для анализа производительности SQL-запросов для <a href="http://blog.sjinks.pro/tag/yii/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Yii">Yii</a></em></h2>
<p>Одной из вещей, которых мне очень не хватало при разработке сайтов на Yii — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа.</p>
<p>Ситуацию частично исправило расширение под названием <a href="http://rmcreative.ru/blog/post/yii-db-profiler">Yii DB profiler</a>. Но остались некоторые неудобства:</p>
<ul>
<li>Отображение запросов в порядке убывания времени выполнения — в принципе, это дело вкуса: при таком порядке сразу видны проблемные запросы. С другой стороны, лично мне более привычен хронологический порядок — так чётче прослеживается логика работы;</li>
<li>Prepared statements. Это просто здорово, но если повторять запрос в phpMyAdmin (например, если интересует план выполнения запроса), бывает очень муторно заменять все связанные значения. Например, для запросов вида
          
<div class="codebox">
    <div class="the_code" style="" id="p9475">
        <div class="code mysql" id="p947code5">
<span class="kw1">SELECT</span> <span class="st0">'t'</span>.<span class="st0">&quot;object<span class="es1">_</span>id&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c0&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;ymd&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c1&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;black&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c2&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;brown&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c3&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;yellow&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c4&quot;</span><span class="sy2">,</span> <br />
<span class="st0">'t'</span>.<span class="st0">&quot;neutral&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c5&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;white&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c6&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;unknown&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c7&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;error&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c8&quot;</span><span class="sy2">,</span> <span class="st0">'object'</span>.<span class="st0">&quot;object&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t1<span class="es1">_</span>c2&quot;</span><span class="sy2">,</span><br />
<span class="st0">'object'</span>.<span class="st0">&quot;id&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t1<span class="es1">_</span>c0&quot;</span><br />
<span class="kw1">FROM</span> <span class="st0">'dnsbl<span class="es1">_</span>summary'</span> <span class="st0">'t'</span> <br />
<span class="kw13">LEFT</span> <span class="kw1">OUTER</span> <span class="kw1">JOIN</span> <span class="st0">'objects'</span> <span class="st0">'object'</span> <span class="kw1">ON</span> <span class="br0">&#40;</span><span class="st0">'t'</span>.<span class="st0">&quot;object<span class="es1">_</span>id&quot;</span><span class="sy1">=</span><span class="st0">'object'</span>.<span class="st0">&quot;id&quot;</span><span class="br0">&#41;</span> <br />
<span class="kw1">WHERE</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span>black <span class="sy1">&gt;</span> 0<span class="br0">&#41;</span> <span class="kw10">OR</span> <span class="br0">&#40;</span>brown <span class="sy1">&gt;</span> 0<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span>ymd<span class="sy1">=</span>:ycp0<span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>black<span class="sy1">&gt;</span>:ycp1<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>brown<span class="sy1">=</span>:ycp2<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>yellow<span class="sy1">=</span>:ycp3<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span>neutral<span class="sy1">&gt;</span>:ycp4<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>white<span class="sy1">&gt;</span>:ycp5<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>unknown<span class="sy1">=</span>:ycp6<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>black<span class="sy1">&gt;</span>:ycp7<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span>error<span class="sy1">=</span>:ycp8<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>object.enabled <span class="sy1">=</span> 1<span class="br0">&#41;</span><br />
<span class="kw1">LIMIT</span> <span class="nu0">50</span>
        </div>
    </div>
</div>

заменять все <code>:ycpXXX</code> на их значения немного муторно. В общем случае здесь вряд ли можно что-то сделать — заполнители параметров могут быть любыми (и даже позиционными), поэтому тупое использование <code>str_replace</code> может наделать делов.
</li>
</ul>
<p>Лично мне список запросов нужен обычно только для двух вещей:</p>
<ol>
<li>Оценка работы механизмов кэширования;</li>
<li>Оценка плана выполнения запроса, составленная оптимизатором.</li>
</ol>
<p>Первое обычно не критично (зачастую достаточно посмотреть на количество запросов), а вот второе позволяет выявить многие будущие проблемы с производительностью заранее.</p>
<p>В результате, взяв за основу <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> <a href="http://rmcreative.ru/">Александра</a>, я портировал <a href="http://blog.sjinks.pro/tag/sqlmon/">SQLMon</a> на Yii.<br />
<span id="more-947"></span></p>
<p>В результате получилось расширение, позволяющее получать планы выполнения запросов в реальном времени.</p>
<p>Поддерживаются <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a> и SQLite, в планах поддержка PgSQL (там не всё просто, ибо Postgres <em>выполняет</em> запрос, что может привести к интересным последствиям при использовании <code>INSERT</code>/<code>UPDATE</code>/<code>DELETE</code>; как следствие, придётся использовать <a href="http://blog.sjinks.pro/php/932-pdo-nested-transactions/">вложенные транзакции</a>).</p>
<p>Вывод результатов осуществляется либо при помощи виджета:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9476">
        <div class="code php" id="p947code6">
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widget</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'ext.sqlmon.components.SQLMon'</span><br />
&nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'explain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения запроса</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'backtrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'dsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения (может быть полезно при использовании нескольких БД)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'cssFile'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="co1">// Эстеты могут задать свой файл стилей </span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Либо при помощи Log Route:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9477">
        <div class="code php" id="p947code7">
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'components'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'log'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'routes'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'class'</span> <span class="sy0">=&gt;</span> <span class="st_h">'ext.sqlmon.components.SQLMonLogRoute'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showExplain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showDsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showBacktrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'class'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'ext.sqlmon.components.SQLMonFileLogRoute'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'logFile'</span> <span class="sy0">=&gt;</span> <span class="st_h">'sqlmon.log'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showExplain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showDsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showBacktrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p><code>SQLMonLogRoute</code> наследуется от <code>CWebLogRoute</code>, но, как и <code>CProfileLogRoute</code>, отказывается выдавать данные для AJAX-запросов.</p>
<p><code>SQLMonFileLogRoute</code> наследуется от <code>CFileLogRoute</code> и, как следствие, воспринимает все параметры конфигурации последнего.</p>
<p>Для того, чтобы протоколирование нормально работало, сообщения от <a href="http://blog.sjinks.pro/tag/sqlmon/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  SQLMon">SQLMon</a> попадают в общий протокол и, как следствие, видны при использовании <code>CWebLogRoute</code> (в этом случае выдаётся минимум информации).</p>
<p>Результаты работы выглядят примерно так (пример приведён для SQLite):</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-yii.png"><img src="http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-yii-300x283.png" alt="Пример выдачи SQLMon" title="SQLMon в Yii" width="300" height="283" class="alignnone size-medium wp-image-948" /></a></p>
<p>Реализовано всё через собственный класс PDO, поэтому для использования SQLMon нужно в файл конфигурации добавить такие строки:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9478">
        <div class="code php" id="p947code8">
<br />
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'import'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'ext.sqlmon.components.*'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<br />
&nbsp; &nbsp; <span class="st_h">'components'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'db'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
<span class="co1">// ...</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'pdoClass'</span> <span class="sy0">=&gt;</span> <span class="st_h">'SQLMonPDO'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Реализация просмотра выполнения плана выполнения запроса осуществляется при помощи класса-наследника от <code>PDOStatement</code> и переопределения метода <code>PDO::prepare()</code>.</p>
<p>Планы на будущее:</p>
<ul>
<li>поддержка PostgreSQL;</li>
<li>возможность расширения классов <code>SQLMonPDO</code> и <code>SQLMonPDOStatement</code> (возможно, придётся позаимствовать некоторые идеи из <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a>);</li>
<li>наследование <code>SQLMon_Explainer_Base</code> от <code>CComponent</code>, что даст дополнительные плюшки для расширяемости;</li>
<li>более красивая реализация функции SQLMon::arr2pre(), что позволит рисовать красивые ASCII-таблички;</li>
<li>возможная поддержка FireBug;</li>
<li>протоколирование в HTML-файл;</li>
<li>информация профайлера MySQL (нужность пока под большим вопросом);</li>
<li>рефакторинг, написание документации</li>
</ul>
<p><strong><a href='http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-0.1.zip'>SQLMon 0.1 for Yii</a></strong> — скачать бесплатно без регистрации без смс <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQLMon для Code Igniter</title>
		<link>http://blog.sjinks.pro/php/769-sqlmon-for-code-igniter/</link>
		<comments>http://blog.sjinks.pro/php/769-sqlmon-for-code-igniter/#comments</comments>
		<pubDate>Sat, 13 Feb 2010 06:10:58 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Code Igniter]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQLMon]]></category>
		<category><![CDATA[оптимизация]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=769</guid>
		<description><![CDATA[Мониторинг SQL-запросов в Code Igniter На днях мне довелось заняться оптимизацией одного проекта, написанного с использованием фреймворка Code Igniter. Важной частью процесса являлась оптимизация запросов к базе данных, а для этого как минимум нужно видеть эти запросы перед глазами. Этот минимум в Code Igniter достигается очень просто: вызовом $this-&#62;output-&#62;enable_profiler(TRUE); в контроллере. Но когда запросов на [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/769-sqlmon-for-code-igniter/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Мониторинг SQL-запросов в <a href="http://blog.sjinks.pro/tag/code-igniter/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Code Igniter">Code Igniter</a></em></h2>
<p>На днях мне довелось заняться оптимизацией одного проекта, написанного с использованием фреймворка Code Igniter. Важной частью процесса являлась <a href="http://blog.sjinks.pro/tag/optimization/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  оптимизация">оптимизация</a> запросов к базе данных, а для этого как минимум нужно видеть эти запросы перед глазами.</p>
<p>Этот минимум в Code Igniter достигается очень просто: вызовом</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76912">
        <div class="code php" id="p769code12">
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">output</span><span class="sy0">-&gt;</span><span class="me1">enable_profiler</span><span class="br0">&#40;</span><span class="kw4">TRUE</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>в контроллере. Но когда запросов на странице очень много, хотелось бы избавиться от рутинного выполнения <span class="codebox"><code class="mysql"><span class="kw1">EXPLAIN</span></code></span> для каждого подозрительного запроса. Что, собственно, и делает <a href="http://blog.sjinks.pro/tag/sqlmon/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  SQLMon">SQLMon</a>. Возникает логичное желание интегрировать его в Code Igniter.<span id="more-769"></span></p>
<p>Но в отличие от <a href="http://blog.sjinks.pro/kohana/762-sqlmon-for-kohana-3/">Kohana</a>, с Code Igniter здесь не всё так просто. Во-первых, Code Igniter не поддерживает так называемую <dfn><a href="http://v3.kohanaphp.com/guide/about.filesystem">каскадную файловую систему</a></dfn>. Во-вторых, Code Igniter <a href="http://codeigniter.com/user_guide/general/creating_libraries.html">не позволяет</a> расширять или заменять класс <code>Database</code>. А изменять код системы (и поддерживать его при каждом обновлении) очень не хочется. Тем не менее, я нашел простое решение и реализовал соответствующую библиотеку.</p>
<p>Перед использованием библиотеки рекомендуется прочитать статью «<a href="http://dev.mysql.com/doc/refman/5.0/en/using-explain.html">Optimizing Queries with EXPLAIN</a>».</p>
<p><strong>Использование библиотеки.</strong> Библиотека состоит из двух частей:</p>
<ol>
<li><strong>Драйвер базы данных</strong> (каталог <code>system/database/drivers/<a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">mysql</a>_exp</code>). Драйвер требует наличия драйвера MySQL (класс <code>CI_DB_mysql_driver</code>), так как, по сути дела, является производным от него классом. Драйвер переопределяет метод <span class="codebox"><code class="php">_execute<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>, в котором и выполняет анализ запроса.</li>
<li><strong>Представление (view).</strong> Находится в каталоге <code>system/application/views/sqlmon</code>, используется для отображения результатов.</li>
</ol>
<p>Установка библиотеки простая: содержимое каталога <code>system/database</code> должен быть скопировано в <code>system/database</code>, содержимое каталога <code>system/application</code> должно быть скопировано в каталог приложения. Затем нужно отредактировать настройки соединения с базой данных (файл <code>appliaction/config/database.<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a></code>): параметр <code>dbdriver</code> соединения нужно установить в <code>mysql_exp</code>.</p>
<p>Пример:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76913">
        <div class="code php" id="p769code13">
<span class="re0">$active_group</span> <span class="sy0">=</span> <span class="st0">&quot;default&quot;</span><span class="sy0">;</span><br />
<span class="re0">$active_record</span> <span class="sy0">=</span> <span class="kw4">TRUE</span><span class="sy0">;</span><br />
<br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'hostname'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;localhost&quot;</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'username'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;username&quot;</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'password'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;password&quot;</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'database'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;database&quot;</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'dbdriver'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;mysql_exp&quot;</span><span class="sy0">;</span> <span class="co1">// &lt;&lt;&lt; Вот оно</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'dbprefix'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;mso_&quot;</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'pconnect'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw4">TRUE</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'db_debug'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw4">TRUE</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'cache_on'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw4">FALSE</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'cachedir'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;system/cache/db&quot;</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'char_set'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;utf8&quot;</span><span class="sy0">;</span><br />
<span class="re0">$db</span><span class="br0">&#91;</span><span class="st_h">'default'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'dbcollat'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st0">&quot;utf8_general_ci&quot;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Затем в соответствующее представление добавляем код:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76914">
        <div class="code php" id="p769code14">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$ci</span> <span class="sy0">=</span> <span class="sy0">&amp;</span>get_instance<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$ci</span><span class="sy0">-&gt;</span><span class="me1">load</span><span class="sy0">-&gt;</span><span class="me1">view</span><span class="br0">&#40;</span><span class="st_h">'sqlmon/sqlmon'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>И наслаждаемся. На выходе должно получиться что-то вида (на примере MaxSite CMS; изображение можно кликнуть):</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2010/02/codeigniter-sqlmon-maxsite.png" rel="lightbox" title="Результат работы SQLMon для Code Igniter на примере MaxSite CMS"><img src="http://static.sjinks.info/wp-content/uploads/2010/02/codeigniter-sqlmon-maxsite-300x292.png" alt="Результат работы SQLMon для Code Igniter на примере MaxSite CMS" title="Результат работы SQLMon для Code Igniter на примере MaxSite CMS" width="300" height="292" class="alignnone size-medium wp-image-770" /></a></p>
<p><strong><a href="http://d.sjinks.pro/sqlmon-ci.zip">Скачать SQLMon для Code Igniter</a>.</strong></p>
<p></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/769-sqlmon-for-code-igniter/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/769-sqlmon-for-code-igniter/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>SQLMon для Kohana 3</title>
		<link>http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/</link>
		<comments>http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 19:16:01 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Kohana]]></category>
		<category><![CDATA[Kohana 3]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQLMon]]></category>
		<category><![CDATA[оптимизация]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=762</guid>
		<description><![CDATA[Мониторинг SQL-запросов в Kohana 3 Продолжая славную традицию реализации SQLMon под различные CMS/фреймворки, написал одному заказчику модуль для Kohana 3. SQLMon для Kohana 3 интегрируется в иерархию классов Database (встраивается между классами Database_MySQL и Kohana_Database_MySQL) и реализует обёртку над методом Kohana_Database_MySQL::query(), измеряя время выполнения запроса, объём потребляемой памяти, записывая код ошибки запроса, трассу вызовов и [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Мониторинг SQL-запросов в <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a> 3</em></h2>
<p>Продолжая славную традицию реализации <a href="http://blog.sjinks.pro/tag/sqlmon/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  SQLMon">SQLMon</a> под различные CMS/фреймворки, написал одному заказчику модуль для <a href="http://blog.sjinks.pro/tag/kohana-3/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana 3">Kohana 3</a>.</p>
<p>SQLMon для Kohana 3 интегрируется в иерархию классов Database (встраивается между классами <code>Database_<a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a></code> и <code>Kohana_Database_MySQL</code>) и реализует обёртку над методом <span class="codebox"><code class="php">Kohana_Database_MySQL<span class="sy0">::</span><span class="me2">query</span><span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>, измеряя время выполнения запроса, объём потребляемой памяти, записывая код ошибки запроса, трассу вызовов и <span class="codebox"><code class="mysql"><span class="kw1">EXPLAIN</span></code></span> запроса (причём не только для <span class="codebox"><code class="mysql"><span class="kw1">SELECT</span></code></span>, но и <span class="codebox"><code class="mysql"><span class="kw1">UPDATE</span></code></span>/<span class="codebox"><code class="mysql"><span class="kw1">DELETE</span></code></span> и <span class="codebox"><code class="mysql"><span class="kw2">INSERT</span></code></span>/<span class="codebox"><code class="mysql"><span class="kw2">REPLACE</span> <span class="kw1">INTO</span> … <span class="kw1">AS</span></code></span> или <span class="codebox"><code class="mysql"><span class="kw1">CREATE</span> &nbsp;<span class="kw1">TABLE</span> … <span class="kw1">AS</span></code></span>) — всё то же самое, что и <a href="http://blog.sjinks.pro/wordpress-plugins/sqlmon/">SQLMon для WordPress</a>.<span id="more-762"></span></p>
<p>Данный модуль будет полезен разработчикам для анализа производительности запросов MySQL и поиска решений для их оптимизации. Перед использованием модуля рекомендуется прочитать статью «<a href="http://dev.mysql.com/doc/refman/5.0/en/using-explain.html">Optimizing Queries with EXPLAIN</a>».</p>
<p><strong>Использование модуля.</strong> Модуль должен быть распакован в каталог <code>modules</code> проекта (после распаковки появится каталог <code>sqlmon</code>). Затем модуль должен быть активирован в файле <code>application/bootstrap.<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a></code>. Очень важно, чтобы модуль подключался <strong>перед модулем <code>database</code></strong> — это связано с <a href="http://v3.kohanaphp.com/guide/about.filesystem">особенностями поиска классов в Kohana 3</a>.</p>
<p>Например:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76218">
        <div class="code php" id="p762code18">
Kohana<span class="sy0">::</span><span class="me2">modules</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'sqlmon'</span> &nbsp; &nbsp; <span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'sqlmon'</span><span class="sy0">,</span> &nbsp; &nbsp; <span class="co1">// SQL Monitor — обязательно перед Database</span><br />
&nbsp; &nbsp; <span class="st_h">'database'</span> &nbsp; <span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'database'</span><span class="sy0">,</span> &nbsp; <span class="co1">// Database access</span><br />
&nbsp; &nbsp; <span class="st_h">'orm'</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'orm'</span><span class="sy0">,</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// Object Relationship Mapping</span><br />
&nbsp; &nbsp; <span class="st_h">'pagination'</span> <span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'pagination'</span><span class="sy0">,</span> <span class="co1">// Paging of results</span><br />
<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Для отображения статистики нужно выполнить</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76219">
        <div class="code php" id="p762code19">
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> View<span class="sy0">::</span><span class="me2">factory</span><span class="br0">&#40;</span><span class="st_h">'sqlmon/sqlmon'</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>Результатом будет нечто вида (скриншот можно кликнуть):</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2010/02/kohana-sqlmon.png" rel="lightbox" title="SQLMon для Kohana — пример работы"><img src="http://static.sjinks.info/wp-content/uploads/2010/02/kohana-sqlmon-300x136.png" alt="SQLMon для Kohana — пример работы" title="SQLMon для Kohana — пример работы" width="300" height="136" class="size-medium wp-image-763" /></a></p>
<p><strong>Настройка.</strong> SQLMon использует файлы конфигурации модуля Database — <code>config/database.php</code>. Для контроля поведения SQLMon нужно использовать параметры:</p>
<ul>
<li><code>backtrace</code> — <code>boolean</code> (по умолчанию true) — должен ли SQLMon отображать трассу вызовов (то, что отображается синим цветом на скриншоте выше);</li>
<li><code>explain</code> — <code>boolean</code> (по умолчанию true) — должен ли SQLMon отображать план выполнения запросов (<span class="codebox"><code class="mysql"><span class="kw1">EXPLAIN</span></code></span>).</li>
</ul>
<p>Пример файла конфигурации:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76220">
        <div class="code php" id="p762code20">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'default'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'type'</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'mysql'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'profiling'</span> &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'charset'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'utf8'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'table_prefix'</span> &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Настройки SQLMon</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'backtrace'</span> &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'explain'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// ---</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'connection'</span> &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'username'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'root'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'password'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'M1dn19ht'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'hostname'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'localhost'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'persistent'</span> <span class="sy0">=&gt;</span> <span class="kw4">false</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'database'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'feedfetcher'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p><strong><a href="http://d.sjinks.pro/kohana/sqlmon.zip">Скачать SQLMon для Kohana 3</a>.</strong></p>
<p></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>SQLMon: плагин для анализа SQL-запросов</title>
		<link>http://blog.sjinks.pro/wordpress/plugins/192-sqlmon-plugin-for-sql-query-analysis/</link>
		<comments>http://blog.sjinks.pro/wordpress/plugins/192-sqlmon-plugin-for-sql-query-analysis/#comments</comments>
		<pubDate>Fri, 13 Jun 2008 00:17:34 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Плагины WordPress]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQLMon]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[плагин]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=192</guid>
		<description><![CDATA[Поиск слабых мест производительности: анализируем SQL-запросы Меня всегда интересовало, насколько эффективно WordPress работает с базой данных, и насколько хорошо спроектирована база данных. Практически в каждом проекте, над которым я работаю, я использую те или иные средства для анализа производительности скрипта и поиска его слабых мест. Для разработчиков не является секретом, что во многих случаях плохая [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/plugins/192-sqlmon-plugin-for-sql-query-analysis/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Поиск слабых мест производительности: анализируем SQL-запросы</em></h2>
<p>Меня всегда интересовало, насколько эффективно <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> работает с базой данных, и насколько хорошо спроектирована база данных.</p>
<p>Практически в каждом проекте, над которым я работаю, я использую те или иные средства для анализа производительности скрипта и поиска его слабых мест. Для разработчиков не является секретом, что во многих случаях плохая <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a> работы скрипта обусловлена низкой производительностью SQL-запросов. И, как правило, низкое быстродействие запросов связано с их неоптимальностью (что включает в себя отсутствие необходимых индексов в базе данных).</p>
<p>Однажды столкнувшись с ужасной производительностью WordPress и не имея возможности анализировать код десятка поставленных плагинов, я стал решать задачу иначе, в результате чего родился <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> для анализа SQL-запросов.<span id="more-192"></span></p>
<p><strong>Принцип работы.</strong> Плагин устанавливает обработчики действий, которые позволяют перехватить запрос к базе данных непосредственно перед его выполнением. Если перехваченный запрос — <code>SELECT</code>, <code>UPDATE</code> или <code>DELETE</code>, то скрипт пытается его «объяснить» — выполнить <code>EXPLAIN</code> над запросом. Предвидя возражения, что <code>EXPLAIN</code> работает только с <code>SELECT</code>, но никак не с <code>DELETE</code> и <code>UPDATE</code>, поясняю: запросы <code>DELETE</code> и <code>UPDATE</code> переписываются в <code>SELECT</code>, например:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p19228">
        <div class="code mysql" id="p192code28">
<span class="kw1">DELETE</span> <span class="st0">`t1`</span><br />
&nbsp; &nbsp; <span class="kw1">FROM</span> <span class="st0">`t1`</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> <span class="st0">`t2`</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">ON</span> <span class="st0">`t1`</span>.<span class="st0">`id`</span> <span class="sy1">=</span> <span class="st0">`t2`</span>.<span class="st0">`id`</span><br />
&nbsp; &nbsp; <span class="kw1">WHERE</span> <span class="st0">`t2`</span>.<span class="st0">`key`</span> <span class="sy1">=</span> <span class="st0">'value'</span><br />
&nbsp; &nbsp; <span class="kw1">LIMIT</span> <span class="nu0">5</span>
        </div>
    </div>
</div>

<p>будет переписан в </p>
          
<div class="codebox">
    <div class="the_code" style="" id="p19229">
        <div class="code mysql" id="p192code29">
<span class="kw1">EXPLAIN</span> <span class="kw1">SELECT</span> <span class="sy1">*</span><br />
&nbsp; &nbsp; <span class="kw1">FROM</span> <span class="st0">`t1`</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> <span class="st0">`t2`</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">ON</span> <span class="st0">`t1`</span>.<span class="st0">`id`</span> <span class="sy1">=</span> <span class="st0">`t2`</span>.<span class="st0">`id`</span><br />
&nbsp; &nbsp; <span class="kw1">WHERE</span> <span class="st0">`t2`</span>.<span class="st0">`key`</span> <span class="sy1">=</span> <span class="st0">'value'</span><br />
&nbsp; &nbsp; <span class="kw1">LIMIT</span> <span class="nu0">5</span>
        </div>
    </div>
</div>

<p>Возможно, переписывание работает не всегда, но такие случаи мне еще не встречались <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Я предполагаю, что Вы понимаете, для чего нужен <code>EXPLAIN</code> и как следует понимать результаты, которые он выдаёт. Если это не так, то очень рекомендую прочитать статью «<a href="http://dev.mysql.com/doc/refman/5.0/en/using-explain.html">Optimizing Queries with EXPLAIN</a>», а затем вернуться к данной статье.</p>
<p>Плагин в футере темы (кстати, это относится и к админке) выдаст подробный <a href="http://blog.sjinks.pro/tag/log/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  лог">лог</a> запросов с их объяснением. Это может выглядеть примерно так:</p>
<p><a href='http://static.sjinks.info/wp-content/uploads/2008/06/querylog.png'><img src="http://static.sjinks.info/wp-content/uploads/2008/06/querylog-300x255.png" alt="Лог SQL-запросов" title="SQL Query Log" class="alignnone size-medium wp-image-193" /></a></p>
<p><strong><a href="http://d.sjinks.pro/wordpress/sqlmon.zip" rel="nofollow">Скачать SqlMon</a>.</strong></p>
<p><strong>Установка.</strong> К сожалению, установка данного плагина полностью не автоматизируется: кое-что надо делать вручную. После активации плагина в WordPress нужно выполнить следующие действия:</p>
<ol>
<li>Добавить в файл <code>/wp-config.<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a></code> следующие строки:
          
<div class="codebox">
    <div class="the_code" style="" id="p19230">
        <div class="code php" id="p192code30">
<span class="kw1">define</span><span class="br0">&#40;</span><span class="st_h">'SQLMON_ENABLED'</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="re0">$sqlmon_allowed_ips</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="st_h">'70.87.222.86'</span><span class="sy0">,</span> <span class="st_h">'195.10.218.132'</span><span class="sy0">,</span> <span class="st_h">'127.0.0.1'</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

Первая строка активирует режим перехвата и анализа запросов, вторая строка содержит массив с IP-адресами, которым <em>разрешен</em> просмотр лога запросов. Естественно, нужно указать свои адреса <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
<li>Далее предстоит пропатчить один файлик WordPress: <code>/wp-includes/wp-db.php</code>. Сразу объясню, зачем это нужно: WordPress не предоставляет нормальных возможностей отловить запрос до его выполнения. Фильтр <code>query</code> для наших целей не подходит: во-первых, последующий плагин может переписать запрос, во-вторых, я уже насмотрелся на плагины, которые лезут переписывать запрос, если видят SELECT. Проверено, что переписывание EXPLAIN SELECT такими плагинами приводит к синтаксической ошибке.
<p>Теперь о том, что нужно менять. В файле <code>/wp-includes/wp-db.php</code> есть класс wpdb, в котором есть метод query. В этом методе нужно найти строки</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p19231">
        <div class="code php" id="p192code31">
<span class="co1">// Perform the query via std mysql_query function..</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span>SAVEQUERIES<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">timer_start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">result</span> <span class="sy0">=</span> <span class="sy0">@</span><span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">dbh</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
<span class="sy0">++</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">num_queries</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>и изменить их:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p19232">
        <div class="code php" id="p192code32">
<span class="co1">// Perform the query via std mysql_query function..</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span>SAVEQUERIES<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">timer_start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">true</span> <span class="sy0">==</span> <span class="kw3">function_exists</span><span class="br0">&#40;</span><span class="st_h">'do_action'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; do_action<span class="br0">&#40;</span><span class="st_h">'before_query'</span><span class="sy0">,</span> <span class="re0">$query</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">dbh</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">result</span> <span class="sy0">=</span> <span class="sy0">@</span><span class="kw3">mysql_query</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">dbh</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">true</span> <span class="sy0">==</span> <span class="kw3">function_exists</span><span class="br0">&#40;</span><span class="st_h">'do_action'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; do_action<span class="br0">&#40;</span><span class="st_h">'after_query'</span><span class="sy0">,</span> <span class="re0">$query</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">dbh</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="sy0">++</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">num_queries</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Для тех, кто предпочитает иметь дело с патчами, привожу <strong><a href="http://d.sjinks.pro/wp-db.php.diff">патч в формате unified diff</a></strong> (<strong>внимание:</strong> патч проверялся только на WordPress&nbsp;2.5.1):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p19233">
        <div class="code diff" id="p192code33">
--- wp-db.old.php &nbsp; &nbsp; &nbsp; 2008-03-21 01:34:32.000000000 +0200 <br />
<span class="re4">+++ wp-db.php &nbsp; <span class="nu0">2008</span>-06-<span class="nu0">13</span> 03:02:<span class="nu0">27.000000000</span> +0300 </span><br />
<span class="re6">@@ -<span class="nu0">272</span>,<span class="nu0">7</span> +<span class="nu0">272</span>,<span class="nu0">16</span> @@ </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>SAVEQUERIES<span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $this-&gt;timer_start<span class="br0">&#40;</span><span class="br0">&#41;</span>; <br />
&nbsp; <br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>true == function_exists<span class="br0">&#40;</span>'do_action'<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> </span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_action<span class="br0">&#40;</span>'before_query', $query, $this-&gt;dbh<span class="br0">&#41;</span>; </span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> </span><br />
<span class="re8">+ </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $this-&gt;result = @mysql_query<span class="br0">&#40;</span>$query, $this-&gt;dbh<span class="br0">&#41;</span>; <br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>true == function_exists<span class="br0">&#40;</span>'do_action'<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> </span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_action<span class="br0">&#40;</span>'after_query', $query, $this-&gt;dbh<span class="br0">&#41;</span>; </span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> </span><br />
<span class="re8">+ </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++$this-&gt;num_queries; <br />
&nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>SAVEQUERIES<span class="br0">&#41;</span>
        </div>
    </div>
</div>

</li>
</ol>
<p>После этого перезагружаем страницу и смотрим <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><ins datetime="2008-08-03T07:44:36+00:00"><strong>Update:</strong></ins> для WordPress&nbsp;2.6 патч будет выглядеть следующим образом:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p19234">
        <div class="code diff" id="p192code34">
--- wp-db.old.php &nbsp; &nbsp; &nbsp; 2008-07-11 04:49:06.000000000 +0300<br />
<span class="re4">+++ wp-db.php &nbsp; <span class="nu0">2008</span>-08-03 <span class="nu0">10</span>:<span class="nu0">39</span>:<span class="nu0">14.000000000</span> +0300</span><br />
<span class="re6">@@ -<span class="nu0">605</span>,<span class="nu0">7</span> +<span class="nu0">605</span>,<span class="nu0">16</span> @@</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span> defined<span class="br0">&#40;</span>'SAVEQUERIES'<span class="br0">&#41;</span> &amp;&amp; SAVEQUERIES <span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $this-&gt;timer_start<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>true == function_exists<span class="br0">&#40;</span>'do_action'<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_action<span class="br0">&#40;</span>'before_query', $query, $this-&gt;dbh<span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></span><br />
<span class="re8">+</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $this-&gt;result = @mysql_query<span class="br0">&#40;</span>$query, $this-&gt;dbh<span class="br0">&#41;</span>;<br />
<span class="re8">+</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>true == function_exists<span class="br0">&#40;</span>'do_action'<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do_action<span class="br0">&#40;</span>'after_query', $query, $this-&gt;dbh<span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></span><br />
<span class="re8">+</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++$this-&gt;num_queries;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span> defined<span class="br0">&#40;</span>'SAVEQUERIES'<span class="br0">&#41;</span> &amp;&amp; SAVEQUERIES <span class="br0">&#41;</span>
        </div>
    </div>
</div>

<p><strong style="color: red">Данная версия плагина больше не поддерживается, так как есть <a href="http://blog.sjinks.pro/wordpress-plugins/sqlmon/">новая версия плагина SQLMon</a>, которая, к тому же, не требует внесения изменений в код WordPress.</strong></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/plugins/192-sqlmon-plugin-for-sql-query-analysis/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/plugins/192-sqlmon-plugin-for-sql-query-analysis/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

