MySQL中针对查询占用CPU过高的SQL进行优化

一、环境

1.1 版本

  • MySQL版本:5.7.25(单机版)
  • 操作系统:CentOS Linux release 8.2.2004

1.2 使用工具

二、问题分析及优化

2.1 现象

(1) 客服报"业务系统中与查询相关的操作均出现不同程度的卡顿"

(2) 在服务主机中观察到mysqld进程cpu占用异常

使用top -H -p 2523命令查看mysqld进程的详情(2523是mysqld的进程号)

诊断_01

    可以看出有单个线程占用CPU异常的高,导致整个MySQL进程占用cpu会飙升到1000%!可以根据PID进一步到数据库中进行跟踪查询查询较慢的sql,不过可以进一步以耗时比较高的进行排序后查看。

2.2 分析

使用Navicat工具登陆数据库后,使用如下命令进行过滤查看

select a.user,a.host,b.thread_os_id,b.thread_id,a.id processlist_id,a.command,a.time,a.state,a.info 
from information_schema.processlist a,`performance_schema`.threads b 
where a.id=b.processlist_id and a.command<>'Sleep'
-- and b.thread_os_id={pid}
order by time desc limit 15;

/*
关于表information_schema.processlist字段说明
· Id:链接 mysql 服务器线程的唯一标识,可以通过 kill 来终止此线程的链接。
· User:当前线程链接数据库的用户
· Host:显示这个语句是从哪个 ip 的哪个端口上发出的。可用来追踪出问题语句的用户
· db: 线程链接的数据库,如果没有则为 null
· Command: 显示当前连接的执行的命令,一般就是休眠或空闲(sleep),查询(query),连接(connect)
· Time: 线程处在当前状态的时间,单位是秒
· State:显示使用当前连接的 sql 语句的状态,很重要的列,后续会有所有的状态的描述,请注意,state 只是语句执行中的某一个状态,一个 sql 语句,已查询为例,可能需要经过 copying · to tmp table,Sorting result,Sending data 等状态才可以完成
· Info: 线程执行的 sql 语句,如果没有语句执行则为 null。这个语句可以使客户端发来的执行语句也可以是内部执行的语句
*/

如果需要跟踪上图中占比最高的线程,可以使用and b.thread_os_id过滤查询,这里直接根据information_schema.processlist.time(单位 秒)进行倒序排列,可以看出更多查询较慢的SQL,便于整体分析。

查询得出如下结果,可以看出,对于查询较慢的SQL,可以一目了然的看出端倪

诊断_02

2.3 定位

    根据分析得出有几张表非常可疑,如t_duration_logt_duration_day_log等,后查询得知,上述几张表的存储记录早已超过500w,甚至达到其数倍,因此要想在不大动业务情况下进行优化,只能从非业务侧进行,如SQL优化、索引优化、业务侧缩小哦查询范围等。

1) SQL优化

    针对查询较慢的SQL语句,执行计划后,针对性的优化。如针对以下表的查询语句,由于只需要查询获取到id列,因此不需要进行order排序,移除order by id desc后可以看出明显rows减少。

SQL优化前

SQL优化后

注意:上述优化,需要在业务侧进行更改后重新打包上线;另外,如果查询出的id列表需要进行排序,可以在业务侧进行而不是在数据库层进行排序。(当order by 字段出现在where条件中时,才会利用索引而无需排序操作。其他情况,order by不会出现排序操作。

2) 索引优化

    根据查询出较慢的SQL,将SQL拷贝到单独窗口中(在Navicat中操作),在SQL最前端使用explain字段执行查询计划(或使用Navicat中的解释按钮),返回执行计划的信息,针对其中使用到全表索引或rows记录明显过多的SQL进行针对性的添加索引。
    如果由于表数据量较大,添加单个字段索引或联合索引耗时较长,可能需要业务侧停服进行操作。
    提示:explain执行计划中type依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL(一般来说,得保证查询达到range级别,最好达到ref)

三 参考

附件

附件A MySQL配置文件

配置文件路径:/etc/my.cnf,内容如下

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/data/mysql
socket=/tmp/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/data/mysql/mysql.pid
#pid-file=/var/lib/mysql/mysql.sock

character_set_server=utf8
#init_connect='SET NAMES utf8'
default-time-zone = '+8:00'

# 默认开启事件
event_scheduler=ON

#数据库唯一ID,主从的标识号绝对不能重复。
server-id=1
#开启bin-log,并指定文件目录和文件名前缀
#log-bin=mysql-bin
#需要同步liting数据库。如果是多个同步库,就以此格式另写几行即可。如果不指明对某个具体库同步,就去掉此行,表示同步所有库(除了ignore忽略的库)。
binlog-do-db=db_sat_boss
binlog-do-db=radius
#不同步mysql系统数据库。如果是多个不同步库,就以此格式另写几行;也可以在一行,中间逗号隔开。
binlog-ignore-db=mysql
#确保binlog日志写入后与硬盘同步
sync_binlog = 1
#跳过现有的采用checksum的事件,mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none
binlog_checksum = none
#bin-log日志文件格式,设置为MIXED可以防止主键重复。
binlog_format = mixed
#二进制日志自动删除/过期的天数。默认值为 0,表示不自动删除。
expire_logs_days    = 10
#如果当前的日志大小达到max_binlog_size,还会自动创建新的二进制日志
max_binlog_size     = 100M
#表示 slave 将复制事件写进自己的二进制日志
log_slave_updates   = 1
#跳过主从复制中遇到的所有错误或指定类型的错误,避免 slave 端复制中断。
slave-skip-errors = all

#自增长起始值
auto-increment-offset = 1
#自增长步长
auto-increment-increment = 2
#临时表大小
tmp_table_size = 64M
#支持group_by
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容