<sect1 id="zend.db.profiler" xmlns:xi="http://www.w3.org/2001/XInclude">

    <title>Zend_Db_Profiler</title>

    <sect2 id="zend.db.profiler.introduction">

        <title>Introducción</title>

        <para>
            <code>Zend_Db_Profiler</code> puede ser habilitado para Perfilar las
            consultas. Los Perfiles incluyen la consulta procesada por el adaptador como
            el tiempo as transcurrido en la ejecución de las consultas, permitiendo
            inspeccionar las consultas realizadas win necesidad de agregar información
            de depuración extra en el código de las clases. El uso avanzado también permite
            que el desarrollador filtre las consultas que desea perfilar.
        </para>

        <para>
            Habilite el perfilador pasando una directiva al al constructor del adaptador,
            o pidiendole al adaptador permitirlo más adelante.
        </para>

        <programlisting role="php"><![CDATA[
$params = array(
    'host'     => '127.0.0.1',
    'username' => 'webuser',
    'password' => 'xxxxxxxx',
    'dbname'   => 'test'
    'profiler' => true  // enciende el perfilador
                        // establezca false para deshabilitar (está deshabilitado por defecto)
);

$db = Zend_Db::factory('PDO_MYSQL', $params);

// apagar el perfilador:
$db->getProfiler()->setEnabled(false);

// encender el perfilador:
$db->getProfiler()->setEnabled(true);
]]>
        </programlisting>

        <para>
            El valor de la opción '<code>profiler</code>' es flexible. Es interpretada de distintas
            formas dependiendo del tipo. Normalmente, debería usar un valor booleano simple, pero
            otros tipos le permiten personalizar el comportamiento del perfilador.
        </para>

        <para>
            Un argumento booleano establece el perfilador como habilitado si el valor es
            <code>true</code>, o deshabilitado si es <code>false</code>. La clase del perfilador
            es el la clase de perfilador por defecto del adaptador, <code>Zend_Db_Profiler</code>.
            <programlisting role="php"><![CDATA[
$params['profiler'] = true;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]>
            </programlisting>
        </para>

        <para>
            Una instancia del objeto perfilador hace que el adaptador use ese objeto.
            El tipo del objeto debe ser <code>Zend_Db_Profiler</code> o una subclase de este.
            Habilitar el perfilador se hace por separado.
            <programlisting role="php"><![CDATA[
$profiler = MyProject_Db_Profiler();
$profiler->setEnabled(true);
$params['profiler'] = $profiler;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]>
            </programlisting>
        </para>

        <para>
            El argumento puede ser un array asociativo conteniendo algunas o todas las claves
            '<code>enabled</code>', '<code>instance</code>', y '<code>class</code>'. Las claves
            '<code>enabled</code>' e '<code>instance</code>' corresponden a los tipos booleano y
            la instancia documentada previamente. La clave '<code>class</code>' es usada para nombrar
            la clase que usará el perfilador personalizado. La clase debe ser
            <code>Zend_Db_Profiler</code> o una subclase. La clase es instanciada sin argumentos
            de constructor. La opción '<code>class</code>' es ignorada cuando la opción
            '<code>instance</code>' está dada.
            <programlisting role="php"><![CDATA[
$params['profiler'] = array(
    'enabled' => true,
    'class'   => 'MyProject_Db_Profiler'
);
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]>
            </programlisting>
        </para>

        <para>
            Finalmente, el argumento puede ser un objeto de tipo <code>Zend_Config</code>
            conteniendo las propiedades, que son tratadas como las claves de array descritas recién.
            Por ejemplo, un archivo "config.ini" puede contener los siguientes datos:
            <programlisting role="ini"><![CDATA[
[main]
db.profiler.class   = "MyProject_Db_Profiler"
db.profiler.enabled = true
]]>
            </programlisting>

            Esta configuración puede ser aplicada con el siguiente código PHP:

            <programlisting role="php"><![CDATA[
$config = new Zend_Config_Ini('config.ini', 'main');
$params['profiler'] = $config->db->profiler;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]>
            </programlisting>

            La propiedad '<code>instance</code>' debe ser usada como el siguiente ejemplo:
            <programlisting role="php"><![CDATA[
$profiler = new MyProject_Db_Profiler();
$profiler->setEnabled(true);
$configData = array(
    'instance' => $profiler
    );
$config = new Zend_Config($configData);
$params['profiler'] = $config;
$db = Zend_Db::factory('PDO_MYSQL', $params);
]]>
            </programlisting>

        </para>

    </sect2>

    <sect2 id="zend.db.profiler.using">

        <title>Usando el Perfilador</title>

        <para>
            En este punto, obtenemos el perfilador usando el método
            <code>getProfiler()</code> del adaptador:
        </para>

        <programlisting role="php"><![CDATA[
$profiler = $db->getProfiler();
]]>
        </programlisting>

        <para>
            Este retorna una instancia del objeto <code>Zend_Db_Profiler</code>. Con
            esta instancia, el desarrollador puede examinar las consultar usando una variedad
            de métodos:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <code>getTotalNumQueries()</code> retorna el número total
                    de consultas que han sido perfiladas.
                </para>
            </listitem>
            <listitem>
                <para>
                    <code>getTotalElapsedSecs()</code> retorna el número total
                    de segundos transcurridos en todas las consultas perfiladas.
                </para>
            </listitem>
            <listitem>
                <para>
                    <code>getQueryProfiles()</code> retorna un array con todos
                    los perfiles de consultas.
                </para>
            </listitem>
            <listitem>
                <para>
                    <code>getLastQueryProfile()</code> retorna el último perfil (más
                        reciente) de consulta, independientemente de si la consulta ha
                        terminado o no (si no lo ha hecho, la hora de finalización será nula).
                </para>
            </listitem>
            <listitem>
                <para>
                    <code>clear()</code> limpia los perfiles de consulta de la pila.
                </para>
            </listitem>
        </itemizedlist>

        <para>
            El valor de retorno de <code>getLastQueryProfile()</code> y
            elementos individuales de <code>getQueryProfiles()</code> son
            <code>Zend_Db_Profiler_Query</code> objetos, que proporcionan la
             capacidad para inspeccionar cada una de las consultas:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <code>getQuery()</code> retorna el texto SQL de la consulta.
                    El texto SQL de una declaración preparada con parámetros es el
                    texto al tiempo en que la consulta fué preparada, por lo que contiene
                    marcadores de posición, no los valores utilizados cuando la
                    declaración se ejecuta.
                </para>
            </listitem>
            <listitem>
                <para>
                    <code>getQueryParams()</code> retorna un array de
                    los valores de los parámetros usados cuando se ejecuta una consulta preparada.
                    Este incluye ambos parámetros y argumentos vinculados al método
                    <code>execute()</code> de la declaración.  Las claves del array
                    son las posiciones (basado en 1) o indices de parámetros nombrados (string).
                </para>
            </listitem>
            <listitem>
                <para>
                    <code>getElapsedSecs()</code> returna el número de segundos
                    que tuvo la consulta al correr.
                </para>
            </listitem>
        </itemizedlist>

        <para>
            La información que <code>Zend_Db_Profiler</code> provee es útil para
            perfilar cuellos de botella en aplicaciones, y para depurar consultas que
            han sido ejecutadas. Por instancia, para ver la consulta exacta que tuvo la
            última ejecución:
        </para>

        <programlisting role="php"><![CDATA[
$query = $profiler->getLastQueryProfile();

echo $query->getQuery();
]]>
        </programlisting>

        <para>
            Tal vez una página se genera lentamente; use el perfilador para
            determinar primero el número total de segundos de todas las consultas,
            y luego recorrer paso a paso a través de las consultas para encontrar
            la más lenta:
        </para>

        <programlisting role="php"><![CDATA[
$totalTime    = $profiler->getTotalElapsedSecs();
$queryCount   = $profiler->getTotalNumQueries();
$longestTime  = 0;
$longestQuery = null;

foreach ($profiler->getQueryProfiles() as $query) {
    if ($query->getElapsedSecs() > $longestTime) {
        $longestTime  = $query->getElapsedSecs();
        $longestQuery = $query->getQuery();
    }
}

echo 'Ejecutadas ' . $queryCount . ' consultas en ' . $totalTime .
     ' segundos' . "\n";
echo 'Promedio de tiempo de consulta: ' . $totalTime / $queryCount .
     ' segundos' . "\n";
echo 'Consultas por segundo: ' . $queryCount / $totalTime . "\n";
echo 'Tardanza de la consulta más lenta: ' . $longestTime . "\n";
echo "Consulta más lenta: \n" . $longestQuery . "\n";
]]>
        </programlisting>

    </sect2>

    <sect2 id="zend.db.profiler.advanced">

        <title>Uso avanzado del Perfilador</title>

        <para>
            Además de la inspección de consultas, el perfilador también le permite
            al desarrollador filtrar que consultas serán perfiladas. El siguiente método
            opera en una instancia de <code>Zend_Db_Profiler</code>:
        </para>

        <sect3 id="zend.db.profiler.advanced.filtertime">
            <title>Filtrar por tiempo transcurrido en consulta</title>

            <para>
                <code>setFilterElapsedSecs()</code> le permite al desarrolador establecer
                un tiempo mínimo antes de que una consulta se perfile. Para remover el filtro,
                pase un valor null al método.
            </para>

            <programlisting role="php"><![CDATA[
// Solo perfilar consultas que tardan más de 5 segundos:
$profiler->setFilterElapsedSecs(5);

// Perfilar todas las consultas sin importar el tiempo:
$profiler->setFilterElapsedSecs(null);
]]>
            </programlisting>
        </sect3>

        <sect3 id="zend.db.profiler.advanced.filtertype">
            <title>Filtrar por tipo de consulta</title>

            <para>
                <code>setFilterQueryType()</code> le permite al desarrollador
                establecer que tipo de consulta serán perfiladas; para perfilar multiples tipos,
                use un "OR" lógico. Los tipos de consulta se definen como las siguientes
                constantes de <code>Zend_Db_Profiler</code>:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        <code>Zend_Db_Profiler::CONNECT</code>: operaciones de
                        conexión o selección de base de datos.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>Zend_Db_Profiler::QUERY</code>: consultas generales
                        a la base de datos que no calzan con otros tipos.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>Zend_Db_Profiler::INSERT</code>: cualquier consulta
                        que agrega filas a la base de datos, generalmente un SQL INSERT.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>Zend_Db_Profiler::UPDATE</code>: cualquier consulta que
                        actualice registros existentes, usualmente un SQL UPDATE.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>Zend_Db_Profiler::DELETE</code>: cualquier consulta
                        que elimine datos existentes, usualmente un SQL DELETE.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>Zend_Db_Profiler::SELECT</code>: cualquier consulta que
                        retorne datos existentes, usualmente un SQL SELECT.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>Zend_Db_Profiler::TRANSACTION</code>: cualquier
                        operación transaccional, tal como iniciar una transacción, confirmar,
                        o revertir.
                    </para>
                </listitem>
            </itemizedlist>

            <para>
                Asi como con <code>setFilterElapsedSecs()</code>, puedes remover cualquier filtro
                existente pasando un <code>null</code> como único argumento.
            </para>

            <programlisting role="php"><![CDATA[
// Perfilar solo consultas SELECT
$profiler->setFilterQueryType(Zend_Db_Profiler::SELECT);

// Perfila consultas SELECT, INSERT, y UPDATE
$profiler->setFilterQueryType(Zend_Db_Profiler::SELECT |
                              Zend_Db_Profiler::INSERT |
                              Zend_Db_Profiler::UPDATE);

// Perfilar consultas DELETE
$profiler->setFilterQueryType(Zend_Db_Profiler::DELETE);

// Remover todos los filtros
$profiler->setFilterQueryType(null);
]]>
            </programlisting>

        </sect3>

        <sect3 id="zend.db.profiler.advanced.getbytype">
            <title>Obtener perfiles por tipo de consulta</title>

            <para>
                Usando <code>setFilterQueryType()</code> puedes reducir los
                perfiles generados. Sin embargo, a veces puede ser más útil
                mantener todos los perfiles, pero ver sólo los que necesita
                en un determinado momento. Otra característica de
                <code>getQueryProfiles()</code> es que puede este filtrado al-vuelo,
                pasando un tipo de consulta(o una combinación lógica de tipos de consulta)
                en el primer; vea <xref linkend="zend.db.profiler.advanced.filtertype" />
                para una lista las constantes de tipo de consulta.
            </para>

            <programlisting role="php"><![CDATA[
// Obtiene solo perfiles de consultas SELECT
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT);

// Obtiene los perfiles de consultas SELECT, INSERT, y UPDATE
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::SELECT |
                                        Zend_Db_Profiler::INSERT |
                                        Zend_Db_Profiler::UPDATE);

// Obtiene solo perfiles de consultas DELETE
$profiles = $profiler->getQueryProfiles(Zend_Db_Profiler::DELETE);
]]>
            </programlisting>

        </sect3>

    </sect2>

    <sect2 id="zend.db.profiler.profilers">
        <title>Perfiladores Especializados</title>

        <para>
            Un Perfilador Especializado es un objeto que hereda de
            <code>Zend_Db_Profiler</code>.  Los Perfiladores Especializados
            tratan la información de perfilado de maneras más especificas.
        </para>

        <xi:include href="Zend_Db_Profiler-Firebug.xml" />

    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
