¿Existe una herramienta como el "SQL Server Profiler" de Microsoft para MySQL? [cerrado]

43

Mientras desarrollo en MySQL, realmente extraño poder activar un generador de perfiles. Creo que SQLyog es un reemplazo suficientemente bueno para el Analizador de consultas, pero no he encontrado una herramienta que funcione como el generador de perfiles SQL.

Para la gente de MySQL que no ha visto el SQL Profiler de Microsoft , aquí hay una captura de pantalla

profiler sql

En mi trabajo anterior, teníamos una herramienta que triunfaba sobre SQL Profiler e incluso nos daba rastros de pila

perfil de altiris

¿Alguien sabe de alguna herramienta como las que mencioné que funcione con MySQL?

(Para su información, puedo hacer que Altiris Profiler funcione con MySQL, pero implicará ejecutar Windows, además, no es realmente un sku de Symantec, por lo que las licencias son realmente difíciles)

Sam Azafrán
fuente

Respuestas:

17

MySQL nunca ha creado un perfil de consulta. Ahora que MySQL está siendo protegido por Oracle, sé que este seguirá siendo el caso.

Sin embargo, no se pierde toda esperanza.

Desde 2007, Percona ha creado algunas herramientas absolutamente maravillosas para todo lo que un desarrollador y un DBA desearían, incluido el perfil de consulta.

El primer conjunto de herramientas de Percona, conocido como MAATKIT , creó un reino para el usuario serio de MySQL. Cuenta con muchas cosas , como:

  • Perfil de consulta
  • Ritmo cardíaco de replicación
  • Gestión de esclavos de replicación
  • Tabla de suma de verificación y sincronización

Percona ha bifurcado recientemente MAATKIT en un conjunto de herramientas más actualizado, conocido hoy como Percona Toolkit . Estas herramientas continuaron donde MAATKIT lo dejó al expandir el ámbito de actividad para el usuario serio de MySQL para incluir cosas como:

  • Comprobación de errores de clave externa
  • Cambio de esquema en línea
  • Planes de explicación visual
  • y más ...

Volviendo a la pregunta original, las herramientas disponibles para el perfil de consultas son

Aquí hay un ejemplo del tipo de información enriquecida que puede derivarse del uso de una de estas herramientas:

Ayudé a un cliente a implementar mk-query-digest para informar las 20 consultas con peor rendimiento cada 20 minutos. Tengo la idea de este video de YouTube . El cliente movería la salida de cualquier consulta incorrecta a memcached, reduciendo así la incidencia de que la consulta afecte la base de datos.

Aquí está el script que hice para llamar a mk-query-digest (examinando solo la lista de procesos)

#!/bin/sh

RUNFILE=/tmp/QueriesAreBeingDigested.txt
if [ -f ${RUNFILE} ] ; then exit ; fi

MKDQ=/usr/local/sbin/mk-query-digest
RUNTIME=${1}
COPIES_TO_KEEP=${2}
DBVIP=${3}

WHICH=/usr/bin/which
DATE=`${WHICH} date`
ECHO=`${WHICH} echo`
HEAD=`${WHICH} head`
TAIL=`${WHICH} tail`
AWK=`${WHICH} awk`
SED=`${WHICH} sed`
CAT=`${WHICH} cat`
WC=`${WHICH} wc`
RM=`${WHICH} rm | ${TAIL} -1 | ${AWK} '{print $1}'`
LS=`${WHICH} ls | ${TAIL} -1 | ${AWK} '{print $1}'`

HAS_THE_DBVIP=`/sbin/ip addr show | grep "scope global secondary" | grep -c "${DBVIP}"`
if [ ${HAS_THE_DBVIP} -eq 1 ] ; then exit ; fi

DT=`${DATE} +"%Y%m%d_%H%M%S"`
UNIQUETAG=`${ECHO} ${SSH_CLIENT}_${SSH_CONNECTION}_${DT} | ${SED} 's/\./ /g' | ${SED} 's/ //g'`

cd /root/QueryDigest
OUTFILE=QP_${DT}.txt
HOSTADDR=${DBVIP}
${MKDQ} --processlist h=${HOSTADDR},u=queryprofiler,p=queryprofiler --run-time=${RUNTIME} > ${OUTFILE}

#
# Rotate out Old Copies
#

QPFILES=QPFiles.txt
QPFILES2ZAP=QPFiles2Zap.txt
${LS} QP_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9].txt > ${QPFILES}

LINECOUNT=`${WC} -l < ${QPFILES}`
if [ ${LINECOUNT} -gt ${COPIES_TO_KEEP} ]
then
        (( DIFF = LINECOUNT - COPIES_TO_KEEP ))
        ${HEAD} -${DIFF} < ${QPFILES} > ${QPFILES2ZAP}
        for QPFILETOZAP in `${CAT} ${QPFILES2ZAP}`
        do
                ${RM} ${QPFILETOZAP}
        done
fi

rm -f ${QPFILES2ZAP}
rm -f ${QPFILES}
rm -f ${RUNFILE}

Aquí está el usuario que hice para conectarme a mysql usando mk-query-digest

GRANT PROCESS ON *.* TO 'queryprofiler'@'%' IDENTIFIED BY 'queryprofiler';

Aquí está el crontab que ejecuté cada 20 minutos (menos 10 segundos) manteniendo las últimas 144 copias (que son 48 horas de creación de perfiles)

*/20 * * * * /root/QueryDigest/ExecQueryDigest.sh 1190s 144 10.1.1.8

La parte increíble: la salida de mk-query-digest

Aquí hay un perfil que se ejecutó el 28/12/2011 11:20:00 durante 1190 segundos (20 minutos menos 10 segundos)

Las últimas 22 líneas.

# Rank Query ID           Response time    Calls   R/Call     Item
# ==== ================== ================ ======= ========== ====
#    1 0x5E994008E9543B29    40.3255 11.2%     101   0.399263 SELECT schedule_occurrence schedule_eventschedule schedule_event schedule_eventtype schedule_event schedule_eventtype schedule_occurrence.start
#    2 0x392F6DA628C7FEBD    33.9181  9.4%      17   1.995184 SELECT mt_entry mt_objecttag
#    3 0x6C6318E56E149036    26.4695  7.3%     102   0.259505 SELECT schedule_occurrence schedule_eventschedule schedule_event schedule_eventtype schedule_event schedule_eventtype schedule_occurrence.start
#    4 0x00F66961DAE6FFB2    25.5472  7.1%      55   0.464495 SELECT mt_entry mt_placement mt_category
#    5 0x99E13015BFF1E75E    22.3618  6.2%     199   0.112371 SELECT mt_entry mt_objecttag
#    6 0x84DD09F0FC444677    22.3516  6.2%      39   0.573118 SELECT mt_entry
#    7 0x440EBDBCEDB88725    21.1817  5.9%      36   0.588380 SELECT mt_entry
#    8 0x8D258C584B858811    17.2402  4.8%      37   0.465951 SELECT mt_entry mt_placement mt_category
#    9 0x4E2CB0F4CAFD1400    16.9768  4.7%      40   0.424419 SELECT mt_entry mt_placement mt_category
#   10 0x377E0D0898266FDD    16.6979  4.6%     150   0.111319 SELECT polls_pollquestion mt_category
#   11 0x3B9686D98BB8E054    16.2089  4.5%      32   0.506529 SELECT mt_entry mt_objecttag mt_tag
#   12 0x97F670B604A85608    15.6158  4.3%      34   0.459287 SELECT mt_entry mt_placement mt_category
#   13 0x3F5557DA231225EB    14.4309  4.0%      36   0.400859 SELECT mt_entry mt_placement mt_category
#   14 0x191D660A10738896    13.1220  3.6%      31   0.423290 SELECT mt_entry mt_placement mt_category
#   15 0xF88F7421DD88036D    12.1261  3.4%      61   0.198788 SELECT mt_entry mt_blog mt_objecttag mt_tag mt_author
#   16 0xA909BF76E7051792    10.3971  2.9%      53   0.196172 SELECT mt_entry mt_objecttag mt_tag
#   17 0x3D42D07A335ED983     9.1424  2.5%      20   0.457121 SELECT mt_entry mt_placement mt_category
#   18 0x59F43B57DD43F2BD     9.0533  2.5%      21   0.431111 SELECT mt_entry mt_placement mt_category
#   19 0x7961BD4C76277EB7     8.5564  2.4%      47   0.182052 INSERT UNION UPDATE UNION mt_session
#   20 0x173EB4903F3B6DAC     8.5394  2.4%      22   0.388153 SELECT mt_entry mt_placement mt_category

Tenga en cuenta que esta es la lista de las 20 consultas con peor rendimiento en función del tiempo de respuesta de la consulta dividido por el número de veces que se llamó a la consulta.

Mirando la ID de consulta # 1, que es 0x5E994008E9543B29, ubicamos esa ID de consulta en el archivo de salida y aquí está el informe para esa consulta en particular:

# Query 1: 0.09 QPS, 0.03x concurrency, ID 0x5E994008E9543B29 at byte 0 __
# This item is included in the report because it matches --limit.
#              pct   total     min     max     avg     95%  stddev  median
# Count          4     101
# Exec time      7     40s   303ms      1s   399ms   992ms   198ms   293ms
# Lock time      0       0       0       0       0       0       0       0
# Users                  1      mt
# Hosts                101 10.64.95.73:33750 (1), 10.64.95.73:34452 (1), 10.64.95.73:38440 (1)... 97 more
# Databases              1     mt1
# Time range 1325089201 to 1325090385
# bytes          0 273.60k   2.71k   2.71k   2.71k   2.62k       0   2.62k
# id             4 765.11M   7.57M   7.58M   7.58M   7.29M    0.12   7.29M
# Query_time distribution
#   1us
#  10us
# 100us
#   1ms
#  10ms
# 100ms  ################################################################
#    1s  ######
#  10s+
# Tables
#    SHOW TABLE STATUS FROM `mt1` LIKE 'schedule_occurrence'\G
#    SHOW CREATE TABLE `mt1`.`schedule_occurrence`\G
#    SHOW TABLE STATUS FROM `mt1` LIKE 'schedule_eventschedule'\G
#    SHOW CREATE TABLE `mt1`.`schedule_eventschedule`\G
#    SHOW TABLE STATUS FROM `mt1` LIKE 'schedule_event'\G
#    SHOW CREATE TABLE `mt1`.`schedule_event`\G
#    SHOW TABLE STATUS FROM `mt1` LIKE 'schedule_eventtype'\G
#    SHOW CREATE TABLE `mt1`.`schedule_eventtype`\G
#    SHOW TABLE STATUS FROM `schedule_occurrence` LIKE 'start'\G
#    SHOW CREATE TABLE `schedule_occurrence`.`start`\G
# EXPLAIN
SELECT `schedule_occurrence`.`id`, `schedule_occurrence`.`schedule_id`, `schedule_occurrence`.`event_id`, `schedule_occurrence`.`start`, `schedule_occurrence`.`end`, `schedule_occurrence`.`cancelled`, `schedule_occurrence`.`original_start`, `schedule_occurrence`.`original_end`, `schedule_occurrence`.`all_day`, `schedule_occurrence`.`ongoing`, `schedule_occurrence`.`featured`, `schedule_eventschedule`.`id`, `schedule_eventschedule`.`event_id`, `schedule_eventschedule`.`start`, `schedule_eventschedule`.`end`, `schedule_eventschedule`.`all_day`, `schedule_eventschedule`.`ongoing`, `schedule_eventschedule`.`min_date_calculated`, `schedule_eventschedule`.`max_date_calculated`, `schedule_eventschedule`.`rule`, `schedule_eventschedule`.`end_recurring_period`, `schedule_eventschedule`.`textual_description`, `schedule_event`.`id`, `schedule_event`.`title`, `schedule_event`.`slug`, `schedule_event`.`description`, `schedule_event`.`host_id`, `schedule_event`.`cost`, `schedule_event`.`age_restrictions`, `schedule_event`.`more_info`, `schedule_event`.`photo_id`, `schedule_event`.`contact_email`, `schedule_event`.`event_type_id`, `schedule_event`.`featured`, `schedule_event`.`staff_pick`, `schedule_event`.`futuremost`, `schedule_event`.`creator_id`, `schedule_event`.`created_on`, `schedule_event`.`allow_comments`, `schedule_event`.`mt_entry`, `schedule_eventtype`.`id`, `schedule_eventtype`.`parent_id`, `schedule_eventtype`.`name`, `schedule_eventtype`.`slug`, `schedule_eventtype`.`lft`, `schedule_eventtype`.`rght`, `schedule_eventtype`.`tree_id`, `schedule_eventtype`.`level`, T5.`id`, T5.`title`, T5.`slug`, T5.`description`, T5.`host_id`, T5.`cost`, T5.`age_restrictions`, T5.`more_info`, T5.`photo_id`, T5.`contact_email`, T5.`event_type_id`, T5.`featured`, T5.`staff_pick`, T5.`futuremost`, T5.`creator_id`, T5.`created_on`, T5.`allow_comments`, T5.`mt_entry`, T6.`id`, T6.`parent_id`, T6.`name`, T6.`slug`, T6.`lft`, T6.`rght`, T6.`tree_id`, T6.`level` FROM `schedule_occurrence` INNER JOIN `schedule_eventschedule` ON (`schedule_occurrence`.`schedule_id` = `schedule_eventschedule`.`id`) INNER JOIN `schedule_event` ON (`schedule_eventschedule`.`event_id` = `schedule_event`.`id`) INNER JOIN `schedule_eventtype` ON (`schedule_event`.`event_type_id` = `schedule_eventtype`.`id`) INNER JOIN `schedule_event` T5 ON (`schedule_occurrence`.`event_id` = T5.`id`) INNER JOIN `schedule_eventtype` T6 ON (T5.`event_type_id` = T6.`id`) WHERE (EXTRACT(MONTH FROM `schedule_occurrence`.`start`) = 8 AND EXTRACT(DAY FROM `schedule_occurrence`.`start`) = 6 AND `schedule_occurrence`.`start` BETWEEN '2011-01-01 00:00:00' and '2011-12-31 23:59:59.99') ORDER BY `schedule_occurrence`.`ongoing` ASC, `schedule_occurrence`.`all_day` DESC, `schedule_occurrence`.`start` ASC\G

Aunque el histograma está basado en texto, proporciona una imagen precisa del rendimiento general de la consulta, a veces se ejecuta durante 1 segundo, y la mayoría de las veces entre 0,01 y 0,1 segundos. A partir de aquí, se puede proceder a ajustar el rendimiento refactorizando la consulta, colocando los resultados de la consulta en memcached, agregando índices faltantes o de cobertura, etc.

CONCLUSIÓN

En mi humilde opinión, si Percona alguna vez colocó las herramientas del generador de perfiles en una GUI de Windows, rivalizaría fácilmente con el Analizador de SQL Server de Microsoft.

Restos de defensa !!!

RolandoMySQLDBA
fuente
En mi humilde opinión, JetProfiler se parece a lo que Percona Tools combinaría gráficamente. Cada uno tiene matices uno sobre el otro. Los usuarios de Linux y las personas de la línea de comandos estarían satisfechos con Percona Tools o MAATKIT. JetProfiler elimina tener que ser como DB en profundidad más la ventaja gráfica de Windows de un MONyog a su disposición.
RolandoMySQLDBA
5

No, no existe tal herramienta.

Sam Azafrán
fuente
Convenido. Descubrí que la mayoría de los desarrolladores / administradores de MySQL nunca han pasado mucho tiempo con Microsoft SQL Server y no se dan cuenta de lo increíble que es la pila MS para el desarrollo. Todas las herramientas de consulta de MySQL que he visto dependen del sondeo, pero SQL Server le permite ver casi todo lo que sucede con la base de datos en tiempo real. No hay nada que se acerque a los detalles de SQL Server Profiler porque MySQL simplemente no lo admite.
parleer
4

MySQL Query Profiler combinado con la herramienta GUI MySQL es probablemente lo más cerca que puede estar de la herramienta SQL Server Profiler


fuente
2
Ay, no hay GUI allí ...
Sam Saffron
Peor aún, todavía no muestra la historia real del tráfico. ¡Wow, Microsoft le quita los calcetines a Oracle en este caso!
4

Las mejores soluciones listas para usar que he encontrado son usar una combinación del registro de consulta lento (que apesta en comparación con Profiler), y simplemente ejecutar Wireshark en el puerto 3306 (que realmente apesta en comparación con Profiler, y ganó ' no funciona si estás encriptando conexiones).

También hay SHOW FULL PROCESSLIST, que es como una combinación reducida de sys.dm_exec_sessions y sys.dm_exec_requests (con un poco de sys.dm_exec_sql_text incluido).

db2
fuente
4

Si necesita crear un perfil de una sola aplicación, y no todas las bases de datos presentes en MySQL, encontrará Neor Profile SQL útil.

Nikl
fuente