N秒后如何自动终止慢速MySQL查询?


16

我正在寻找一个经过良好测试的bash脚本(或替代解决方案)来这样做,以避免max_connection耗尽。我知道它正在解决症状,但确实需要这样的脚本作为短期解决方案。


您正在运行什么版本的MySQL ???
RolandoMySQLDBA 2012年

mysql版本是5.5
alfish 2012年

Answers:


21

percona工具箱中检出pt-kill命令。

和..不要开始监控系统- 穆宁仙人掌MySQL的更好的仙人掌模板,任何事情,所以你得到一些想法发生了什么事情。记录mysql慢查询也是一个好主意。


感谢您的建议,但实际上需要一个“一次性”脚本。
alfish 2012年

5
pt-kill经过了很好的测试,可以解决您的确切问题。找出命令行参数并使其运行大约需要10分钟。您还想要什么?
亚伦·布朗

12

如果您的MySQL 5.1的进程列表位于INFORMATION_SCHEMA中,则可以执行以下操作从mysql客户端中批量生成KILL QUERY命令,以查询运行时间超过20分钟(1200秒)的查询:

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

您可以针对INFO字段执行WHERE子句以查找特定查询,针对长期运行的查询执行TIME字段,或者针对特定数据库执行DB字段。

如果您是root @ localhost,则应该具有完全权限来按以下方式运行它

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

您可以按以下步骤进行crontab:

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

这是另一种变化:

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

顺便说一句,由于我从information_schema.processlist显式读取为完全限定的表名,因此您没有指定myDB。

这是您应该看到的演示。对于此示例,我将回显所有时间> 20000秒的进程的KILL命令:

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

在过去的五年中,我一直在使用这种技术。实际上,我去年曾将此答案提交给DBA StackExchange并被接受


罗兰,能否请您澄清以下几点:该命令是持久性的,还是需要经常运行?假设mysql用户为“ root”且数据库名称为myDB,应在命令中替换什么?谢谢
alfish 2012年

我更新了答案。
RolandoMySQLDBA 2012年

谢谢,但是将您的最后一个食谱变成bash脚本后,我在第1行得到:错误1064(42000),您的SQL语法有错误;检查手册对应到你的MySQL服务器版本,在1号线附近使用“”正确的语法
alfish

哪个SQL命令生成该错误?
RolandoMySQLDBA 2012年

Roland SF不是沙盒。最好在建议解决方案之前进行测试。另外,当所有连接都饱和时,假设它没有故障,mysql将如何运行您的过程?
alfish 2012年

6

我在这里找到了以下代码片段:

2013年1月14日更新:匿名提示说,这潜在危险,并且也可能终止复制过程。因此,使用风险自负:

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

上面的代码段中的时间常数是多少?
alfish 2012年

@alfish我不是作者-但我想说这是一个正则表达式,它匹配具有至少两位数字的所有时间值。因此,这里的假设是10太长。
尼尔斯2012年

1

从MySQL 5.7开始,您可以使用max_execution_time变量针对所有“ SELECT”读取查询自动完成此操作。


0

如果您希望正常运行时间,我不会尝试bash解决方案!

如果您有权访问代码,则可以使用此处概述的方法实际设置SELECT语句的最大执行时间:

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

否则,在服务器上:

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

安装pt-kill:

$ wget percona.com/get/pt-kill

为您的流程列表创建快照:

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

在快照上测试pt-kill:

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

确保匹配规则适合您的情况。以上这些将在45秒内杀死所有Execute语句。确定后,请修改并运行此命令以10秒的间隔执行该语句:

$ ./pt-kill -u root -p myreallyimportantpassword --busy-time 45 --kill-busy-commands 'Execute' --victims all --interval 10 --kill
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.