当前位置:首页 » 编程语言 » 慢sql怎么办
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

慢sql怎么办

发布时间: 2023-07-17 12:26:11

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

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

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

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

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

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

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

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

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

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

在这里插入图片描述

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

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

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

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


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

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

在这里插入图片描述

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

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


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

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

Linux操作系统中

Windows操作系统中

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


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

使用命令:


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

简单说明:

切记

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

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

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

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

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

通过命令

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

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

mysqlmpslow 常用的使用逗庆方式如下:

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

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

其他常用方式:

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

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

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

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!!!!

㈡ 如何解决SQL查询速度太慢

1. 执行计划中明明有使用到索引,为什么执行还是这么慢?

2. 执行计划中显示扫描行数为 644,为什么 slow log 中显示 100 多万行?
a. 我们先看执行计划,选择的索引 “INDX_BIOM_ELOCK_TASK3(TASK_ID)”。结合 sql 来看,因为有 "ORDER BY TASK_ID DESC" 子句,排序通常很慢,如果使用了文件排序性能会更差,优化器选择这个索引避免了排序。
那为什么不选 possible_keys:INDX_BIOM_ELOCK_TASK 呢?原因也很简单,TASK_DATE 字段区分度太低了,走这个索引需要扫描的行数很大,而且还要进行额外的排序,优化器综合判断代价更大,所以就不选这个索引了。不过如果我们强制选择这个索引(用 force index 语法),会看到 SQL 执行速度更快少于 10s,那是因为优化器基于代价的原则并不等价于执行速度的快慢;
b. 再看执行计划中的 type:index,"index" 代表 “全索引扫描”,其实和全表扫描差不多,只是扫描的时候是按照索引次序进行而不是行,主要优点就是避免了排序,但是开销仍然非常大。
Extra:Using where 也意味着扫描完索引后还需要回表进行筛选。一般来说,得保证 type 至少达到 range 级别,最好能达到 ref。
在第 2 点中提到的“慢日志记录Rows_examined: 1161559,看起来是全表扫描”,这里更正为“全索引扫描”,扫描行数确实等于表的行数;
c. 关于执行计划中:“rows:644”,其实这个只是估算值,并不准确,我们分析慢 SQL 时判断准确的扫描行数应该以 slow log 中的 Rows_examined 为准。
4. 优化建议:添加组合索引 IDX_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID)

优化过程:
TASK_DATE 字段存在索引,但是选择度很低,优化器不会走这个索引,建议后续可以删除这个索引:
select count(*),count(distinct TASK_DATE) from T_BIOMA_ELOCK_TASK;+------------+---------------------------+| count(*) | count(distinct TASK_DATE) |+------------+---------------------------+| 1161559 | 223 |+------------+---------------------------+

在这个 sql 中 REL_DEVID 字段从命名上看选择度较高,通过下面 sql 来检验确实如此:
select count(*),count(distinct REL_DEVID) from T_BIOMA_ELOCK_TASK;+----------+---------------------------+| count(*) | count(distinct REL_DEVID) |+----------+---------------------------+| 1161559 | 62235 |+----------+---------------------------+

由于有排序,所以得把 task_id 也加入到新建的索引中,REL_DEVID,task_id 组合选择度 100%:
select count(*),count(distinct REL_DEVID,task_id) from T_BIOMA_ELOCK_TASK;+----------+-----------------------------------+| count(*) | count(distinct REL_DEVID,task_id) |+----------+-----------------------------------+| 1161559 | 1161559 |+----------+-----------------------------------+

在测试环境添加 REL_DEVID,TASK_ID 组合索引,测试 sql 性能:alter table T_BIOMA_ELOCK_TASK add index idx_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID);
添加索引后执行计划:
这里还要注意一点“隐式转换”:REL_DEVID 字段数据类型为 varchar,需要在 sql 中加引号:AND T.REL_DEVID = 000000025xxx >> AND T.REL_DEVID = '000000025xxx'

执行时间从 10s+ 降到 毫秒级别:
1 row in set (0.00 sec)
结论
一个典型的 order by 查询的优化,添加更合适的索引可以避免性能问题:执行计划使用索引并不意味着就能执行快。

㈢ 大神们帮忙看看这个SQL语句执行有点慢,要怎么优化才变快点

你好,根据SQL,我给予一些建议,最好根据执行计划:

  1. 若走的全表扫描,建议建立表间关联字段索引,查看索引失效原因,修改SQL关联逻辑,大部分都能解决。

  2. 如果是数据量大的问题:

    a. 如果有多个查询条件,建议建立where限制条件,减少数据统计范围。

    b. 如果实时性要求不高,可以定时跑批,把结果放在结果表里,前台查询结果表。

    c. 关联表太多,SQL建议拆分两端,sum统计单独放一个SQL。

㈣ SQL 语句执行很慢是怎么回事

到这个数量级的全部更新,肯定会很慢。x0dx0a第一。你的记录不一定在同一个partition,x0dx0a第二。不明白为什么那么多人建议你建索引,你建的索引越多,你的更新速度越慢,因为你更新记录的同时,还有更新索引。x0dx0a第三。你必须知道更新速度慢的瓶颈在哪里。是读写太多,还是内存不够,还是CUP不够快,然后对症下药。x0dx0ax0dx0a下面介绍两个简单的办法,也许有效:x0dx0a第一:x0dx0a把这个100W行的表纵向劈成两个,用外键关系连接,一个装小的,经常改变的数据比如ID,外键,状态值,时间等,另一个装大的,不经常改变的数据,比如很长的字符串,xml,text 等。x0dx0a这样更新时操作小的这个表,可以大大节约内存和CPU 开销,降低磁盘操作。x0dx0a坏处就是查询时会慢些。 x0dx0a第二:x0dx0a把这100W行横向切成很多个表,比如每个月的记录装在一个表里,这样每个表的记录数可能只有几万,查询,更新都会快很多。x0dx0a坏处是查询,更新都不如原来好写。

㈤ 为什么我的SQL数据库变的很慢

如果开始的时候不是这样,那应该是数据量过大,你可以考虑备份部分数据,然后再删掉数据库中的数据;还有可能就是你电脑软件装多了,使电脑变慢了;当然,也很有可能是中毒了,杀杀毒试试

㈥ 如何解决SQL查询速度太慢

呵呵,这个问题很有趣不是吗?
上面的同志们只是给出一些建议,以我的经验来看(oracle),
如果数据量较大,索引的重复量尽量避免,最好的方式是建立非业务id(最好使用自增或是序列),把这个id建立索引。
你的最大的问题就是,建立了索引后,索引列必须出现在where中,否则索引就白白建立了,比如你的id是从1一直到383000,那么你的语句可以写成
select
*
from
hr_worktime
where
id>-1
还有就是,where条件中避免出现!=,or,between,等东西,否则索引实效。