Existe-t-il un outil comme «SQL Server Profiler» de Microsoft pour MySQL? [fermé]


43

Tout en développant sur MySQL, il me manque vraiment de pouvoir lancer un profileur. Je trouve que SQLyog remplace suffisamment l'analyseur de requêtes, mais je n'ai pas trouvé d'outil qui fonctionne comme le profileur SQL.

Pour les utilisateurs de MySQL qui n'ont pas vu SQL Profiler de Microsoft , voici une capture d'écran

profileur sql

A mon emploi précédent, nous avions un outil qui surpassait SQL Profiler et nous donnait même des traces de pile

profileur altiris

Est-ce que quelqu'un connaît des outils, comme ceux que j'ai mentionnés, qui fonctionnent avec MySQL?

(Pour info, je peux faire fonctionner Altiris Profiler avec MySQL mais cela impliquera d’exécuter Windows. En outre, ce n’est pas vraiment un sku Symantec, la licence est donc vraiment délicate)

Réponses:


17

MySQL n'a jamais mis au point le profil de requête. Maintenant que MySQL bénéficie des droits acquis d’Oracle, je sais que cela continuera d’être le cas.

Pourtant, tout espoir n'est pas perdu.

Depuis 2007, Percona propose des outils absolument merveilleux pour tout ce qu'un développeur et un administrateur de base de données souhaiteraient, notamment le profilage des requêtes.

Le premier ensemble d'outils de Percona , appelé MAATKIT , a créé un domaine pour les utilisateurs sérieux de MySQL. Il comporte beaucoup de choses , telles que:

  • Profilage de requête
  • Replication Heartbeat
  • Gestion des esclaves de réplication
  • Somme de contrôle de table et synchronisation

Percona a récemment ajouté MAATKIT à un ensemble d’outils plus moderne , connu aujourd’hui sous le nom de Percona Toolkit . Ces outils ont été repris par MAATKIT en élargissant le domaine d'activité pour les utilisateurs sérieux de MySQL afin d'inclure des éléments tels que:

  • Vérification d'erreur de clé étrangère
  • Changement de schéma en ligne
  • Visual Explain Plans
  • et plus ...

Pour en revenir à la question initiale, les outils disponibles pour le profilage de requête sont

Voici un exemple du type d'informations riches pouvant provenir de l'utilisation de l'un de ces outils:

J'ai aidé un client à implémenter mk-query-digest à signaler les 20 requêtes les moins performantes toutes les 20 minutes. J'ai eu l'idée de cette vidéo YouTube . Le client transfèrerait les résultats de toutes les requêtes incorrectes vers memcached, ce qui réduirait l'incidence des requêtes sur la base de données.

Voici le script que j'ai créé pour appeler mk-query-digest (analyse de la liste de processus uniquement)

#!/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}

Voici l'utilisateur que j'ai créé pour me connecter à mysql à l'aide de mk-query-digest

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

Voici la crontab que j'ai exécutée toutes les 20 minutes (moins de 10 secondes) en conservant les 144 derniers exemplaires (ce qui représente 48 heures de profilage).

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

La partie incroyable: La sortie de mk-query-digest

Voici un profil qui a fonctionné 2011-12-28 11:20:00 pour 1190 sec (20 min moins 10 sec)

Les 22 dernières lignes

# 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

Notez qu'il s'agit de la liste des 20 requêtes les moins performantes basée sur le temps de réponse à la requête, divisée par le nombre de fois où la requête a été appelée.

En examinant l'ID de requête n ° 1, à savoir 0x5E994008E9543B29, nous localisons cet ID de requête dans le fichier de sortie et voici le rapport pour cette requête particulière:

# 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

Bien que l'histogramme soit basé sur du texte, il donne une image précise des performances globales de la requête, qui peut parfois durer plus d'une seconde, et la plupart du temps entre 0,01 et 0,1 seconde. À partir de là, on peut procéder au réglage des performances en restructurant la requête, en plaçant les résultats de la requête dans memcached, en ajoutant des index manquants ou couvrants, etc.

CONCLUSION

IMHO Si Percona plaçait jamais les outils de génération de profils dans une interface graphique Windows, il rivaliserait facilement avec Microsoft SQL Server Profiler.

La défense repose !!!


IMHO JetProfiler ressemble à ce que serait Percona Tools combiné graphiquement. Chacun a des nuances les unes sur les autres. Les utilisateurs de Linux et les utilisateurs de ligne de commande seraient satisfaits de Percona Tools ou de MAATKIT. JetProfiler vous évite d'avoir à utiliser une base de données aussi complète que l'avantage graphique Windows d'un MONyog à votre disposition.
RolandoMySQLDBA


5

Non, il n'y a pas un tel outil.


D'accord. J'ai constaté que la plupart des développeurs / administrateurs de MySQL n'ont jamais passé beaucoup de temps avec Microsoft SQL Server et ne réalisent pas à quel point la pile MS est incroyable pour le développement. Chaque outil de requête MySQL que j'ai vu dépend de l'interrogation, mais SQL Server vous permet de surveiller presque tout ce qui se passe avec la base de données en temps réel. Il n’existe aucun élément de détail sur SQL Server Profiler, car MySQL ne le prend tout simplement pas en charge.
parle

4

MySQL Query Profiler associé à l' interface graphique Les outils MySQL sont probablement aussi proches que possible de l'outil SQL Server Profiler.


2
Ouch, il n'y a pas d'interface graphique là-bas ...
Sam Saffron

Pire encore, il ne montre toujours pas l’historique du trafic. Wow, Microsoft souffle les chaussettes d'Oracle sur celui-ci!

4

Les meilleures solutions clés en main que j'ai trouvées sont d'utiliser une combinaison du journal de requête lent (ce qui est nul par rapport à Profiler) et d'exécuter simplement Wireshark sur le port 3306 (qui est vraiment nul par rapport à Profiler). ne fonctionne pas si vous chiffrez des connexions).

Il y a aussi SHOW FULL PROCESSLIST, qui est une combinaison réduite de sys.dm_exec_sessions et de sys.dm_exec_requests (avec un peu de sys.dm_exec_sql_text jeté).


4

Si vous avez besoin de profiler une seule application, et pas toutes les bases de données présentes sur MySQL, vous trouverez utile Neor Profile SQL .




En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.