it-swarm.it

Esiste uno strumento come Microsoft "SQL Server Profiler" per MySQL?

Durante lo sviluppo su MySQL mi manca molto la possibilità di accendere un profiler. Trovo SQLyog è un sostituto abbastanza buono per Query Analyzer ma non ho trovato uno strumento che funzioni come il profiler SQL.

Per la gente di MySQL che non ha visto Microsoft SQL Profiler , ecco uno screenshot

profiler sql

Nel mio lavoro precedente avevamo uno strumento che trumped SQL Profiler e ci forniva persino tracce dello stack

altiris profiler

Qualcuno sa di eventuali strumenti come quelli che ho citato che funziona con MySQL.

(Cordiali saluti, posso far funzionare Altiris Profiler con MySQL, ma coinvolgerà anche l'esecuzione di Windows, non è proprio uno sku Symantec, quindi le licenze sono davvero complicate)

43
Sam Saffron

No, non esiste tale strumento.

5
Sam Saffron

MySQL non ha mai creato profili di query. Ora che MySQL viene nonno da Oracle, so che continuerà a essere così.

Tuttavia, ogni speranza non è persa.

Dal 2007, Percona ha messo a punto alcuni strumenti assolutamente meravigliosi per tutto ciò che uno sviluppatore e un DBA vorrebbero, incluso il profilo delle query.

Il primo set di strumenti di Percona, noto come [~ # ~] maatkit [~ # ~] , ha creato un regno per il utente serio di MySQL. Presenta molte cose , come:

  • Profilazione delle query
  • Battito cardiaco di replica
  • Gestione degli slave di replica
  • Tabella Checksum e sincronizzazione

Percona ha recentemente convertito MAATKIT in un set di strumenti più aggiornato, oggi noto come Percona Toolkit . Questi strumenti hanno ripreso da dove MAATKIT si è interrotto espandendo il regno delle attività per l'utente serio di MySQL per includere cose come:

  • Controllo errori chiave esterna
  • Modifica dello schema online
  • Piani esplicativi visivi
  • e altro ancora ...

Tornando alla domanda originale, sono gli strumenti disponibili per la profilazione delle query

Ecco un esempio del tipo di informazioni dettagliate che possono derivare dall'uso di uno di questi strumenti:

Ho aiutato un cliente a implementare mk-query-digest per segnalare le 20 query con le prestazioni peggiori ogni 20 minuti. Ho avuto l'idea da questo video di YouTube . Il client sposterebbe l'output di qualsiasi query non valida in memcached, riducendo così l'incidenza del fatto che la query abbia un tributo sul database.

Ecco lo script che ho creato per chiamare mk-query-digest (examing solo la process list)

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

Ecco l'utente che ho fatto per connettermi a mysql usando mk-query-digest

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

Ecco il crontab che ho eseguito ogni 20 minuti (meno 10 secondi) mantenendo le ultime 144 copie (ovvero 48 ore di profilazione)

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

La parte incredibile: l'output di mk-query-digest

Ecco un profilo che ha funzionato il 28/12/2011 alle 11:20:00 per 1190 sec (20 min meno 10 sec)

Le ultime 22 righe

# 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

Si noti che questo è l'elenco delle 20 query con le prestazioni peggiori basate sul Tempo di risposta alle query diviso per il Numero di volte in cui è stata chiamata la query.

Esaminando l'ID query n. 1, che è 0x5E994008E9543B29, individuiamo tale ID query nel file di output ed ecco il rapporto per quella particolare query:

# 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

Sebbene l'istogramma sia basato su testo, fornisce un quadro accurato delle prestazioni complessive della query, a volte in esecuzione per 1 secondo e la maggior parte del tempo tra 0,01 e 0,1 secondi. Da qui, si può procedere all'ottimizzazione delle prestazioni refactoring della query, collocando i risultati della query in memcached, aggiungendo indici mancanti o coprenti, ecc.

CONCLUSIONE

IMHO Se Percona avesse mai inserito gli strumenti del profiler in una GUI di Windows, avrebbe potuto competere facilmente con il SQL Server Profiler di Microsoft.

Resti di difesa !!!

17
RolandoMySQLDBA
8
Peter

Se devi profilare una singola applicazione e non tutti i database presenti su MySQL, troverai Neor Profile SQL utile.

4
Nikl

MySQL Query Profiler combinato con GUI MySQL tools è probabilmente il più vicino possibile allo strumento SQL Server Profiler

4
Jay

Le migliori soluzioni pronte all'uso che ho trovato sono l'uso di una combinazione del log delle query lente (che fa schifo rispetto a Profiler), e semplicemente eseguendo Wireshark sulla porta 3306 (che davvero fa schifo rispetto a Profiler e non funzionerà se stai crittografando le connessioni).

C'è anche SHOW FULL PROCESSLIST, che è come una combinazione ridotta di sys.dm_exec_sessions e sys.dm_exec_requests (con un piccolo sys.dm_exec_sql_text inserito).

4
db2

Abbiamo 6 server di grandi dimensioni che eseguono varie versioni di MySQL dalla 4.1.22 alla 5.1. Jet profiler buon strumento che ci consente di vedere graficamente lo stato di tutti i server a colpo d'occhio. Visual profiler http://tinyurl.com/profiler-png

3
Ssoon

Vorrei suggerire che la cosa più vicina a questa è Optimizer Trace (novità in 5.6).

Un altro esempio potrebbe essere SHOW PROFILES (5.1+) o performance_schema , che ha un'analisi a livello di istruzione da MySQL 5.6+.

3
Morgan Tocker

Vedi questo risposta sul profiler di MySql LogMonitor

2
nmiranda