百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

美团面试题:慢SQL有遇到过吗?是怎么解决的?

moboyou 2025-03-14 16:31 9 浏览

大家好,我是田维常,可以叫我老田,也可以叫我田哥

。2017年的时候,我刚去上海,朋友内推我去美团面试,之前我也写过一个一篇文章,也是在美团面试中遇到的:

美团面试题:String s = new String("111")会创建几个对象?

关于慢SQL,我和面试官扯了很久,面试官也是很谦虚的,总是点头,自己以为回答的还可以。最后的最后,还是说了“你先回去等通知吧!”。

所以,我决定把这个慢SQL技术点,好好和你分享分享。希望你下次在遇到类似的面试,能顺顺利利轻轻松松的斩获自己想要的offer。

人生最大的喜悦是每个人都说你做不到,你却完成它了!

什么是慢SQL?

MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录MySQL中查询时间超过(大于)设置阈值(long_query_time)的语句,记录到慢查询日志中。

其中,long_query_time的默认值是10,单位是秒,也就是说默认情况下,你的SQL查询时间超过10秒就算慢SQL了。

如何开启慢SQL日志?

在MySQL中,慢SQL日志默认是未开启的,也就说就算出现了慢SQL,也不会告诉你的,如果需要知道哪些SQL是慢SQL,需要我们手动开启慢SQL日志的。

关于慢SQL是否开启,我们可以通过下面这个命令来查看:

-- 查看慢查询日志是否开启
show variables like '%slow_query_log%';

在这里插入图片描述

通过命令,我们就可以看到slow_query_log项为OFF,说明我们的慢SQL日志并未开启。另外我们也可以看到我们慢SQL日志存放于哪个目录下和日志文件名。

下面我们来开启慢SQL日志,执行下面的命令:

set global slow_query_log = 1;

这里需要注意,这里开启的是我们当前的数据库,并且,我们重启数据库后会失效的。

开启慢SQL日志后,再次查看:


slow_query_log项已经变成ON,说明开启成功。

上面说过慢SQL默认时间是10秒,我们通过下面的命令就可以看到我们慢SQL的默认时间:

show variables like '%long_query_time%';

在这里插入图片描述

我们总不能一直使用这个默认值,可能很多业务需要时间更短或更长,所以此时,我们就需要对默认时间进行修改,修改命令如下:

set long_query_time = 3;

修改完了,我们再来看看是否已经改成了3秒。


这里需要注意:想要永久的生效,还需要修改MySQL下面的配置文件my.cnf 文件。

[mysqld]
slow_query_log=1
slow_query_log_file=/var/lib/mysql/atguigu-slow.log
long_query_time=3
log_output=FILE

注意:不同操作系统,配置有些区别。

Linux操作系统中

在mysql配置文件my.cnf中增加

log-slow-queries=/var/lib/mysql/slowquery.log (指定日志文件存放位置,可以为空,系统会给一个缺省的文件host_name-slow.log)

long_query_time=2 (记录超过的时间,默认为10s)

log-queries-not-using-indexes (log下来没有使用索引的query,可以根据情况决定是否开启)

log-long-format (如果设置了,所有没有使用索引的查询也将被记录)

Windows操作系统中

在my.ini的[mysqld]添加如下语句:

log-slow-queries = E:\web\mysql\log\mysqlslowquery.log

long_query_time = 3(其他参数如上)

执行一条慢SQL,因为我们前面已经设置好了慢SQL时间为3秒,所以,我们只要执行一条SQL时间超过3秒即可。

SELECT SLEEP(4);


该SQL耗时4.024秒,下面我们就来查看慢SQL出现了多少条。

使用命令:

show global status like '%Slow_queries%';


查询SQL历程

找到慢SQL日志文件,打开后就会出现类似下面这样的语句;

# Time: 2021-07-20T09:17:49.791767Z
# User@Host: root[root] @ localhost []  Id:   150
# Query_time: 0.002549  Lock_time: 0.000144 Rows_sent: 1  Rows_examined: 4079
SET timestamp=1566292669;
select * from city where Name = 'Salala';

简单说明:

1.Time 该日志记录的时间

2.User @Host MySQL登录的用户和登录的主机地址

3.Query_time一行 第一个时间是查询的时间、第二个是锁表的时间、第三个是返回的行数、第四个是扫描的行数

4.SET timestamp 这一个是MySQL查询的时间

5.sql语句 这一行就很明显了,表示的是我们执行的sql语句

切记

如果你将long_query_time=0 ,那就意味着,我们所有的查询SQL语句都会输出到慢SQL日志文件中。

如何定位慢SQL?

通常我们定位慢SQL有两种方式:

第一种:定位慢查询SQL可以通过两个表象进行判断

  • 系统级表象:
    • 使用sar命令和top命令查看当前系统的状态
    • 也可以使用PrometheusGrafana监控工具查看当前系统状态
    • CPU消耗严重
    • IO等待严重
    • 页面响应时间过长
    • 项目日志出现超时等错误
  • SQL语句表象:
    • SQL语句冗长
    • SQL语句执行时间过长
    • SQL从全表扫描中获取数据
    • 执行计划中的rowscost很大

第二种:根据不同的数据库使用不同的方式获取问题SQL

  • MySQL:
    • 慢查询日志
    • 测试工具loadrunner
    • ptquery工具
  • Oracle:
    • AWR报告
    • 测试工具loadrunner
    • 相关内部视图vsession_wait
    • GRID CONTROL监控工具

熟悉慢SQL日志分析工具吗?

如果开启了慢SQL日志后,可能会有大量的慢SQL日志产生,此时再用肉眼看,那是不太现实的,所以大佬们就给我搞了个工具:mysqldumpslow

mysqldumpslow能将相同的慢SQL归类,并统计出相同的SQL执行的次数,每次执行耗时多久、总耗时,每次返回的行数、总行数,以及客户端连接信息等。

通过命令

mysqldumpslow --help

可以看到相关参数的说明:

~# mysqldumpslow --help
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]

Parse and summarize the MySQL slow query log. Options are

  --verbose    verbose
  --debug      debug
  --help       write this text to standard output

  -v           verbose
  -d           debug
  -s ORDER     what to sort by (al, at, ar, c, l, r, t), 'at' is default
                al: average lock time
                ar: average rows sent
                at: average query time
                 c: count
                 l: lock time
                 r: rows sent
                 t: query time  
  -r           reverse the sort order (largest last instead of first)
  -t NUM       just show the top n queries
  -a           don't abstract all numbers to N and strings to 'S'
  -n NUM       abstract numbers with at least n digits within names
  -g PATTERN   grep: only consider stmts that include this string
  -h HOSTNAME  hostname of db server for *-slow.log filename (can be wildcard),
               default is '*', i.e. match all
  -i NAME      name of server instance (if using mysql.server startup script)
  -l           don't subtract lock time from total time

比较常用的参数有这么几个:

-s 指定输出的排序方式
   t  : 根据query time(执行时间)进行排序;
   at : 根据average query time(平均执行时间)进行排序;(默认使用的方式)
   l  : 根据lock time(锁定时间)进行排序;
   al : 根据average lock time(平均锁定时间)进行排序;
   r  : 根据rows(扫描的行数)进行排序;
   ar : 根据average rows(扫描的平均行数)进行排序;
   c  : 根据日志中出现的总次数进行排序;
-t 指定输出的sql语句条数;
-a 不进行抽象显示(默认会将数字抽象为N,字符串抽象为S);
-g 满足指定条件,与grep相似;
-h 用来指定主机名(指定打开文件,通常慢查询日志名称为“主机名-slow.log”,用-h exp则表示打开exp-slow.log文件);

使用方式

mysqldumpslow常用的使用方式如下:

# mysqldumpslow -s c slow.log

如上一条命令,应该是mysqldumpslow最简单的一种形式,其中-s参数是以什么方式排序的意思,c指代的是以总数从大到小的方式排序。-s的常用子参数有:c: 相同查询以查询条数和从大到小排序。t: 以查询总时间的方式从大到小排序。l: 以查询锁的总时间的方式从大到小排序。at: 以查询平均时间的方式从大到小排序。al: 以查询锁平均时间的方式从大到小排序。

同样的,还可以增加其他参数,实际使用的时候,按照自己的情况来。

其他常用方式:

# 得到返回记录集最多的10 个SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log

# 得到访问次数最多的10 个SQL
mysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log

# 得到按照时间排序的前10 条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/atguigu-slow.log

# 另外建议在使用这些命令时结合| 和more 使用,否则有可能出现爆屏情况
mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log | more

接下,我们来个实际操作。

实操

root@yunzongjitest1:~# mysqldumpslow -s t -t 3

Reading mysql slow query log from /var/lib/mysql/exp-slow.log /var/lib/mysql/yunzongjitest1-slow.log
Count: 464  Time=18.35s (8515s)  Lock=0.01s (3s)  Rows=90884.0 (42170176), root[root]@localhost
  select ************

Count: 38  Time=11.22s (426s)  Lock=0.00s (0s)  Rows=1.0 (38), root[root]@localhost
  select *********** not like 'S'

Count: 48  Time=5.07s (243s)  Lock=0.02s (1s)  Rows=1.0 (48), root[root]@localhost
  select ********='S'

这其中的SQL语句因为涉及某些信息,所以我都用*号将主体替换了,如果希望得到具体的值,使用-a参数。

使用mysqldumpslow查询出来的摘要信息,包含了这些内容:

Count: 464 :表示慢查询日志总共记录到这条sql语句执行的次数;

Time=18.35s (8515s):18.35s表示平均执行时间(-s at),8515s表示总的执行时间(-s t);

Lock=0.01s (3s):与上面的Time相同,第一个表示平均锁定时间(-s al),括号内的表示总的锁定时间(-s l)(也有另一种说法,说是表示的等待锁释放的时间);

Rows=90884.0 (42170176): 第一个值表示扫描的平均行数(-s ar),括号内的值表示扫描的总行数(-s r)。

是不是

so easy!!!!


来源:
https://mp.weixin.qq.com/s/Cuv8zwDmFSzp9DGqEw8zhg

作者:田维常

相关推荐

记一次前端逻辑绕过登录到内网挖掘

前言在测试一个学校网站的时候发现一个未授权访问内网系统,但是这个未授权并不是接口啥的,而是对前端js的审计和调试发现的漏洞,这里给大家分享一下这次的漏洞的过程文章中涉及的敏感信息均已做打码处理,文...

陕西普通话等级查询网的开发者被指将考生数据直接写入源码里

据报道,陕西普通话等级查询网站突然引起大量程序员关注。有人晒出该网站的源代码的打码截图,图中显示,所有考生数据都被直接写在该网站的源代码里。这表示任何人不需要经过任何验证直接查看源代码即可访问考生信息...

PHP8知识详解:PHP是什么?

PHP是什么?PHP服务网从下面几点为你讲清楚什么是PHP。1、PHP最开始是PersonalHomePage(个人主页)的缩写,已经正式更名为“PHP:HypertextPreproces...

PHP紧急更新修复漏洞:自5.x以来所有版本均受影响

IT之家6月8日消息,PHP项目维护团队昨日发布新补丁,修复了存在于PHPforWindows中的远程代码执行(RCE)漏洞,并敦促用户尽快更新至6月6日发布的8.3.8、...

OA协同办公系统源码解析

在如今的信息化时代,PHPOA软件承当着为企事业单位提供安全、稳定、开源的信息化安全系统,在当今信息化时代,协同办公系统成为了企业管理的重要工具。OA(OfficeAutomation)协同办公系统...

附源码:PHP实现查询汉字笔画、笔画排序

有时候我们在开发中可能会用到和汉字有关的方法,例如笔画排序之类的,但是直接进行sort排序往往得不到我们想要的结果,因为内部并没有预留这些排序方法。因此我们需要自己动手,今天就教大家实现汉字笔画的...

StrongShop跨境电商系统源码 | 支持多语言多货币

StrongShop跨境电商系统源码|支持多语言多货币StrongShop是一款免费开源的跨境电商商城网站。基于PHPLaravel框架开发的一款Web商城系统。该项目在没有对Lar...

源代码的定义

源代码是程序员在开发程序时(通常是在字处理程序中)编写的人类可读指令的列表。源代码通过编译器将其转换为机器代码,也称为目标代码,计算机可以理解和执行。目标代码主要由1和0组成,所以它是不可读的。源代码...

2077年了,PHP语言现在怎么样啦?

“PHP是世界上最好的语言!”这句话一出来,编程界的鄙视链一触即发,程序员的键盘世界大战就爆发了。那么,本文就简单讨论PHP语言,笔者作为创业小公司小团队的角度来妄议一下PHP。首先直接说明观点:新手...

开源直播系统源码—为什么要使用PHP语言

开展开源直播系统源码的的开发工作的时候,开发人员们碰到的最多问题便是使用什么语言开发的,回答大多是PHP语言。而对于没有的开发经验的人而言,难以理解PHP语言究竟代表着什么,又有哪些作用。实际上,PH...

手游平台源码搭建使用的PHP是什么?有什么优点吗?

PHP即“超文本预处理器”,是在服务器端执行的脚本语言,尤其适用于Web开发并可嵌入html中。PHP结合了C语言、java和perl多个语言的特色发展出自己的特色语法,并依据它们的长项持续改进提升自...

PHP直播源码,直播系统源代码功能有哪些?

PHP直播源码究竟是什么?其实所谓的PHP直播源码就是用PHP语言开发的直播系统源代码。PHP是什么?PHP原始为PersonalHomePage的缩写,已经正式更名为“PHP:Hyperte...

盘点如何利用PHP生成PDF文件

在PHP代码中生成PDF文件是一项非常耗时的工作,早期的程序员通常是在PHP代码中利用FPDF生成PDF文件。但在如今,有很多的函数库可以使用,借助它们你可以从你提供的HTML文档生成PDF文件,从而...

PHP低代码开发平台 V5.0.7新版发布

注意:本版变更:此版本增加租户内测模式,同时增加软删除及数据回收功能。Sfdp更新6.0.5版本Tpflow更新6.0.7版本1.[修复]修复数据为空的时桌面方案报错修复了在桌面组件删除时,由于用户...

「sabre/dav」只要十行代码让你的网站获得WebDav网盘能力

如今网盘已经成为我们日常中很重要的工具了,不仅仅可以和别人分享,更重要的是可以在我们不同的设备之间读取资料.那什么是WebDav呢?WebDav是一个Http上封装的一个文件系统,就像ftp,nfs之...