导致sql执行速度慢的几种情况盘点(生产环境踩过的坑)
作者:程序员拾山 发布时间:2024-01-17 17:07:21
前言
当我们遇到慢sql,第一反应可能就是去优化我们的sql语句。一些比较复杂的语句如果执行慢可能还能理解,但是有时一些特别简单的查询也会变得卡顿,“查一行”,也会执行得特别慢。今天,我们盘点一下,都有哪些情况会导致sql执行速度慢。
1,数据库本身压力较大
如果数据库本身的性能压力就比较大,资源比较紧张,CPU占用率或者IO利用率很高,这时会导致所有的语句执行起来都比较慢。这种情况下首先要做的应该是提升服务器的配置,然后观察服务器的性能指标是否平稳。
2,表锁冲突
如果遇到一个简单的查询长时间未返回结果,那么大概率是表被锁住了。一般遇到这种情况,都是通过show processlist命令,查看sql语句的状态。
如图所示,id为8的语句正在等待一个MDL锁,我们可以使用kill命令杀掉这个阻塞线程。
另外还可以通过表sys.schema_table_lock_waits查询阻塞的线程id。
3,行锁冲突
mysql> select * from temp where id =3 for update;
当我们访问id=3这条记录时,使用了for update,表示要对这条语句加锁。但是如果此时已经有另一个事务对这条记录加了锁,并且一直持有不释放锁,那么当前语句就会一直阻塞。
通过上图可以看出,第一个语句不提交事务,第二个语句就一直处于等待阻塞状态。
我们执行show processlist,
可以看出确实有一个线程处于阻塞状态。
锁冲突会导致执行效率降低,进而影响到业务,需要我们重点关注。
4,索引未命中
mysql> select * from t where c=50000 limit 1;
如果字段c上面没有索引,那么就只能走主键id顺序扫描,一直扫描到第50000行才能停下来。
给表数据加索引可以快速提升查询性能,一般来说,因为索引失效导致的慢sql可能是我们平常开发过程中经常遇到的。
5,多表join查询
有了索引,并不代表万事大吉。如果一个比较复杂的sql,需要关联很多表进行查询,即使每张表的索引都可以起到作用,但是由于数据量过多,即使都命中索引,扫描的行数仍然是巨大的。这样sql的执行速度仍然会受到很大影响。
一般来说,超过3个表的join就应该尽量避免,将其拆分为多个查询,使用空间换时间也不失为一个好办法。
补充知识:慢 SQL 语句的几种常见诱因
1. 无索引、索引失效导致
慢查询如果在一张几千万数据的表中以一个没有索引的列作为查询条件,大部分情况下查询会非常耗时,这种查询毫无疑问是一个慢 SQL 查询。
所以对于大数据量的查询,需要建立适合的索引来优化查询。虽然我们很多时候建立了索引,但在一些特定的场景下,索引还有可能会失效,所以索引失效也是导致慢查询的主要原因之一。
2. 锁等待
常用的存储引擎有 InnoDB 和 MyISAM,前者支持行锁和表锁,后者只支持表锁。
如果数据库操作是基于表锁实现的,试想下,如果一张数据表在更新时,需要锁住整张表,那么其它大量数据库操作(包括查询)都将处于等待状态,这将严重影响到系统的并发性能。这时,InnoDB 存储引擎支持的行锁更适合高并发场景。
行锁升级为表锁的可能:
在批量更新操作时,行锁就很可能会升级为表锁。
MySQL 认为如果对一张表使用大量行锁,会导致事务执行效率下降,从而可能造成其它事务长时间锁等待和更多的锁冲突问题发生,致使性能严重下降,所以 MySQL 会将行锁升级为表锁。还有,行锁是基于索引加的锁,如果我们在更新操作时,条件索引失效,那么行锁也会升级为表锁。
因此,基于表锁的数据库操作,会导致 SQL 阻塞等待,影响执行速度。
行锁相对表锁来说,虽然粒度更细,并发能力提升了,但也带来了死锁的问题。因此,在使用行锁时,我们要注意避免死锁。
3. 不恰当的 SQL 语句
使用不恰当的 SQL 语句也是慢 SQL 最常见的诱因之一 :
在大数据表中使用 分页查询,以及对非索引字段进行排序等等。
来源:https://blog.csdn.net/qq_33312725/article/details/128010225


猜你喜欢
- 一些大型站点都有着非常一流的视觉外观,它们很可能在设计时使用了网格系统。网格可以是页面布局显得紧凑而且稳定,为设计师在设计站点时提供一个逻辑
- 话说网站首页是用.NET语言写的,而二级栏目页却是用ASP写的,然后再配上众多全手工的静态专题页,整个网站形成了一个大杂烩。想要在这大杂烩中
- 物质世界客观存在,而人的“视觉成像”是对当前世界的“唯心”重建。这种重建基于个人“经验”、“感知”和“集体意识”。最初科学家认为人类通过视觉
- Python脚本有一个毛病,当使用相对路径时,被另一个不同目录下的py文件中导入时,会报找不到对应文件的问题。感觉是当前工作目录变成了导入p
- 适配器设计模式是懒得改动某些代码,或者某些接口不方便改动的时候,使用一个特定的封装,一些特定的编写办法,使不同的接口可以使用同种调用方式使用
- 完整项目地址下载:https://github.com/rainbow-tan/rainbow/tree/master/%E8%A3%81%
- 一、UDP编程1.客户端Client:发起访问的一方。2.服务器端3.server段编程(1)建立socket,socket是负责具体通信的
- 本文实例为大家分享了python绘制圆柱体示的具体代码,供大家参考,具体内容如下#!/usr/bin/env pythonimport vt
- 一个简单的php文件下载源代码,虽不支持断点续传等,但是可以满足一些常用的需求了。php下载文件其实用一个a标签就能实现,比如 <a
- Django的Form主要具有一下几大功能:生成HTML标签验证用户数据(显示错误信息)HTML Form提交保留上次提交数据初始化页面显示
- 本文实例讲述了Python面向对象程序设计之继承与多继承。分享给大家供大家参考,具体如下:1. 继承在C++和Java中,使用继承时,子类的
- django rest framework使用django-filter注意事项:一定要在setting文件里面加载如下代码,而不是只安装包
- 封装是一个将Python数据对象转化为字节流的过程,拆封是封装的逆操作,将字节文件或字节对象中的字节流转化为Python数据对象,不要从不收
- 问题:每次打开pycharm打开py文件光标都是insert模式, 像下面图片那样解决方案:讲Tools里面的Vim Emulator勾选去
- SQL Server 2000中存在的许多的备份和恢复特性都同样保留在了SQL Server 2005中,但是有一些新的提高同样值得我们关注
- 函数:split()Python中有split()和os.path.split()两个函数,具体作用如下:split():拆分字符串。通过指
- 1.前期准备用户models.pyclass User(models.Model): username = mod
- 下表列出了所有Python语言支持的逻辑运算符。假设变量a持有10和变量b持有20,则: 示例:试试下面的例子就明白了所有的Pyt
- 如下所示:#!/usr/bin/env python#coding: utf8import getpassdb = {}def newUse
- 其中使用到一个分页类CPaging 代码如下:Class CPaging Public RS