N saniye sonra yavaş MySQL sorgularını otomatik olarak nasıl öldürebilirim?


16

Ben max_connection bitmesini önlemek için, bunu yapmak için iyi test edilmiş bir bash script (veya alternatif çözüm) arıyorum. Semptomlarla savaştığını biliyorum, ancak kısa süreli bir çözüm olarak gerçekten senaryoya ihtiyaç duyuyorum.


Hangi MySQL sürümünü kullanıyorsunuz ???
RolandoMySQLDBA

mysql sürümü 5.5
alfish

Yanıtlar:


21

percona araç setinden pt-kill komutunu kontrol edin .

- ve .. sisteminizi izleme başlarım Munin , kaktüs ile daha iyi kaktüsler mysql için şablonlar size ne oluyor bazı fikir edinmek böylece, herhangi bir şey. mysql yavaş sorguları günlüğe kaydetmek de iyi bir fikir olacaktır.


Öneriler için teşekkürler, ancak gerçekten bir kerelik bir komut dosyası arayın.
alfish

5
pt-kill çok iyi test edilmiştir ve tam sorununuzu çözer. Komut satırı parametrelerini bulmak ve çalışmasını sağlamak yaklaşık 10 dakika sürer. Daha fazla İstediğiniz ne?
Aaron Brown

12

İşlem listesinin BİLGİ_SCHEMA'da bulunduğu MySQL 5.1'iniz varsa, bunu 20 dakikadan (1200 saniye) daha uzun süren sorgu için mysql istemcisinden toplu olarak KILL QUERY komutlarını oluşturmak için yapabilirsiniz:

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

Belirli bir sorguyu, uzun süren sorgulara karşı ZAMAN alanını veya belirli bir veritabanına karşı DB alanını aramak için BİLGİ alanına karşı WHERE yan tümceleri yapabilirsiniz.

Root @ localhost iseniz, bunu aşağıdaki gibi çalıştırmak için tam ayrıcalıklara sahip olmalısınız

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

Bunu aşağıdaki gibi crontab edebilirsiniz:

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

İşte başka bir varyasyon:

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

BTW Information_schema.processlist'ten tam olarak nitelenmiş bir tabename olarak açıkça okuduğum için bir myDB belirtmeniz gerekmez.

İşte ne görmeniz gerektiğini gösteren bir örnek. Bu örnek için, zamanı> 20000 saniye olan tüm işlemlerin KILL komutunu yankılayacağım:

[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@***** ~]#

Bu tekniği son 5 yıldır yapıyorum. Aslında, bu cevabı geçen yıl DBA StackExchange'e gönderdim ve kabul edildi .


Roland, lütfen bunları açıklığa kavuşturabilir misiniz? Bu komut kalıcı mıdır yoksa sık çalıştırılması mı gerekir? Mysql kullanıcısının 'root' ve veritabanı adının myDB olduğu varsayılarak komutta ne değiştirilmelidir? Teşekkürler
alfish

Cevabımı güncelledim.
RolandoMySQLDBA

Teşekkürler, ancak son tarifinizi bir bash betiğine çevirdikten sonra, şunu alıyorum: Satır 1'de ERROR 1064 (42000): SQL sözdiziminizde bir hata var; 1. satırda '' yakınında kullanılacak doğru sözdizimi için MySQL sunucu sürümünüze karşılık gelen kılavuzu kontrol edin
alfish

Hangi SQL komutu bu hatayı üretti ???
RolandoMySQLDBA

Roland SF bir sanal alan değil. Çözüm olarak bir şey önermeden önce test etmek daha iyidir. Ayrıca, tüm bağlantılar doygun olduğunda, mysql hatalı olmadığını varsayarak prosedürünüzü nasıl çalıştıracaktır?
alfish

6

Ben burada aşağıdaki kod snipped bulundu :

2013-01-14 Güncellemesi : Bunun potansiyel olarak tehlikeli olduğu ve çoğaltma işlemlerini de öldürebileceği konusunda anonim bir ipucu vardı. Bu yüzden kendi sorumluluğunuzdadır kullanın:

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

Yukarıdaki pasajdaki zaman sabiti nedir?
alfish

@alfish Yazar değilim - ama bunun en az iki basamaklı tüm zaman değerleriyle eşleşen normal bir ifade olduğunu söyleyebilirim. Yani buradaki varsayım 10'un çok uzun olduğudur.
Nils

1

MySQL 5.7 ve sonrasında tüm "SELECT" okuma sorguları için bunu otomatik olarak yapmak için max_execution_time değişkenini kullanabilirsiniz.


0

Çalışma süresini seviyorsanız bash çözümlerini denemem!

Koda erişiminiz varsa, burada özetlenen yöntemi kullanarak SELECT ifadelerinde maksimum yürütme süresini ayarlayabilirsiniz :

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

Aksi takdirde, sunucuda:

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

Pt-kill'i yükleyin:

$ wget percona.com/get/pt-kill

İşlem listenizin bir anlık görüntüsünü alın:

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

Anlık görüntüde pt-kill'i test edin:

$ ./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

Eşleşme kurallarının davanıza uygun olduğundan emin olun. Yukarıda belirtilenler 45 saniye boyunca tüm Execute deyimlerini öldürecektir. Emin olduktan sonra, ifadeyi 10 saniyelik aralıklarla çalıştırmak için bu komutu değiştirin ve çalıştırın:

$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.