Come eliminare automaticamente le query lente di MySQL dopo N secondi?


16

Sto cercando uno script bash ben collaudato (o una soluzione alternativa) per farlo, al fine di evitare che max_connection sia esaurito. So che sta combattendo i sintomi, ma ha davvero bisogno di una sceneggiatura come soluzione a breve termine.


Quale versione di MySQL stai eseguendo ???
RolandoMySQLDBA,

la versione mysql è 5.5
alfish il

Risposte:


21

controlla il comando pt-kill dal toolkit percona .

e .. inizia a monitorare il tuo sistema: munin , cactus con migliori template di cactus per mysql , qualsiasi cosa in modo da avere un'idea di cosa stia succedendo. anche la registrazione delle query lente di mysql sarà una buona idea.


Grazie per i suggerimenti, ma cerca davvero uno script "unico".
alfish

5
pt-kill è molto ben testato e risolve il tuo esatto problema. Ci vogliono circa 10 minuti per capire i parametri della riga di comando e farlo funzionare. Cosa volete di più?
Aaron Brown,

12

Se hai MySQL 5.1 in cui l'elenco dei processi si trova in INFORMATION_SCHEMA, puoi farlo per generare in blocco i comandi KILL QUERY dall'interno del client mysql per query che durano più di 20 minuti (1200 secondi):

SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery
FROM information_schema.processlist WHERE user<>'system user'
AND time >= 1200\G

È possibile eseguire clausole WHERE sul campo INFO per cercare una query specifica, il campo TIME su query a esecuzione prolungata o il campo DB su un database specifico.

Se sei root @ localhost, dovresti avere i privilegi completi per eseguire questo come segue

SECONDS_TOO_LONG=1200
KILLPROC_SQLSTMT="SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" | mysql -uroot -ppassword

Puoi crontab questo come segue:

SECONDS_TOO_LONG=1200
QUERIES_RUNNING_TOO_LONG=`mysql -uroot -ppassword -ANe"SELECT COUNT(1) FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"`
if [ ${QUERIES_RUNNING_TOO_LONG} -gt 0 ]
then
    KILLPROC_SQLSTMT="SELECT GROUP_CONCAT(CONCAT('KILL QUERY ',id,';') SEPARATOR ' ') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
    mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" | mysql -uroot -ppassword
fi

Ecco un'altra variante:

SECONDS_TOO_LONG=1200
QUERIES_RUNNING_TOO_LONG=`mysql -uroot -ppassword -ANe"SELECT COUNT(1) FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"`
if [ ${QUERIES_RUNNING_TOO_LONG} -gt 0 ]
then
    KILLPROC_SQLSTMT="SELECT CONCAT('KILL QUERY ',id,';') KillQuery FROM information_schema.processlist WHERE user<>'system user' AND time >= ${SECONDS_TOO_LONG}"
    mysql -uroot -ppassword -ANe"${KILLPROC_SQLSTMT}" > /tmp/kill_log_queries.sql
    mysql -uroot -ppassword < /tmp/kill_log_queries.sql
fi

A proposito, non hai specificato un myDB poiché ho letto esplicitamente da information_schema.processlist come un nome tabl completo.

Ecco una dimostrazione di ciò che dovresti vedere. Per questo esempio, farò eco al comando KILL di tutti i processi il cui tempo> 20000 secondi:

[root@***** ~]# mysql `lwdba_connect` -ANe"SELECT GROUP_CONCAT('KILL ',id,'; ' SEPARATOR ' ') FROM information_schema.processlist WHERE time > 25000 AND user<>'system user';"
+----------------------------------------------------+
| KILL 180186;  KILL 180141;  KILL 176419;  KILL 3;  |
+----------------------------------------------------+
[root@***** ~]#

Faccio questa tecnica da 5 anni. In effetti, ho inviato questa risposta al DBA StackExchange lo scorso anno ed è stata accettata .


Roland, potresti chiarire queste cose: questo comando è persistente o deve essere eseguito di frequente? Cosa dovrebbe essere sostituito nel comando supponendo che l'utente mysql sia 'root' e il nome del database sia myDB? Grazie
alfish il

Ho aggiornato la mia risposta.
RolandoMySQLDBA,

Grazie, ma dopo aver trasformato la tua ultima ricetta in uno script bash, ottengo: ERRORE 1064 (42000) alla riga 1: hai un errore nella sintassi SQL; controlla il manuale corrispondente alla versione del tuo server MySQL per la sintassi corretta da usare vicino a '' alla riga 1
alfish

Quale comando SQL ha generato quell'errore ???
RolandoMySQLDBA,

Roland SF non è una sandbox. Meglio testare prima di suggerire qualcosa come soluzione. Inoltre, quando tutte le connessioni sono sature, in che modo mysql eseguirà la procedura, supponendo che non sia difettosa?
alfish

6

Ho trovato il seguente frammento di codice qui :

Aggiornamento 2013-01-14: c'è stato un indizio anonimo del fatto che questo è potenzialmente pericoloso e può anche uccidere i processi di replica. Quindi utilizzare a proprio rischio:

mysql -e 'show processlist\G' |\
egrep -b5 'Time: [0-9]{2,}' |\
grep 'Id:' |\
cut -d':' -f2 |\
sed 's/^ //' |\
while read id
do
  mysql -e "kill $id;"
done

Qual è la costante di tempo nello snippet sopra?
alfish

@alfish Non sono l'autore - ma direi che questa è un'espressione regolare che corrisponde a tutti i valori temporali che hanno almeno due cifre. Quindi l'ipotesi qui è che 10 sia troppo lungo.
Nils,

1

Da MySQL 5.7 in poi puoi usare la variabile max_execution_time per farlo automaticamente per tutte le query di lettura "SELECT".


0

Non proverei soluzioni bash se ti piacciono i tempi di attività!

Se hai accesso al codice, puoi effettivamente impostare il tempo massimo di esecuzione sulle istruzioni SELECT usando il metodo descritto qui :

SELECT 
MAX_EXECUTION_TIME = 1000 --in milliseconds
* 
FROM table;

Altrimenti, sul server:

/programming/415905/how-to-set-a-maximum-execution-time-for-a-mysql-query

Installa pt-kill:

$ wget percona.com/get/pt-kill

Scatta un'istantanea del tuo elenco di processi:

$ mysql -u root -B -pmyreallyimportantpassword -e "show processlist;" > processlist.txt

Prova pt-kill sull'istantanea:

$ ./pt-kill --test-matching processlist.txt --busy-time 45 --kill-busy-commands 'Execute' --victims all --print
# 2019-02-25T17:34:37 KILL 45710302 (Execute 374 sec) SELECT\n\tCOUNT(DISTINCT(LP.sessionId))\nFROM lp_traffic LP\nINNER JOIN orders O ON O.orderId = LP.order
# 2019-02-25T17:34:37 KILL 45713515 (Execute 67 sec) SELECT \n\tCOUNT(DISTINCT(CASE WHEN T.response = 'SUCCESS' AND T.isVoid = 0 AND (T.txnType IN

Assicurati che le regole della partita siano adatte al tuo caso. Queste sopra uccideranno tutte le istruzioni Execute per 45 secondi. Dopo esserti assicurato, modifica ed esegui questo comando per eseguire l'istruzione a intervalli di 10 secondi:

$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.