当前位置: 首页 > news >正文

总结:SQL查询变慢,常见原因分析!

文章目录

  • 引言
  • SQL查询慢原因
  • 索引失效
    • 特殊情况-执行计划中,key有值,还是很慢怎么办?
  • 多表JOIN
    • 为什么互联网公司都不建议使用多表join?
  • 索引基数太小不合理
  • 查询字段太多
  • 表中数据量太大
  • 数据库连接数不够
  • 为什么乐观锁还会导致大量的锁耗时呢?
  • 数据库表结构不合理
  • 数据库IO或者CPU比较高
  • 存在长事务
  • 锁竞争导致的等待
  • 数据库参数不合理

引言

在面试中,SQL调优是一个常见的问题,通过这个问题可以考察应聘者对于提升SQL性能的理解和掌握程度。通常来说,SQL调优需要按照以下步骤展开。

首先,需要发现问题。最好结合具体业务情况,比如某次线下报警显示出现了慢SQL,或者接口响应时间较长,经过性能分析发现问题出现在SQL查询上。无论何种情况,都要有一个背景故事。

一旦问题被确定,就需要进行问题分析了。接着首先要定位具体的SQL语句,这可以通过各种监控工具或平台来实现。一旦定位到SQL语句,就能知道是哪张表、哪个SQL语句在拖慢性能。

SQL查询慢原因

1、索引失效
2、多表连接
3、查询字段过多
4、数据量过大
5、索引字段基数太小
6、数据库连接不足
7、数据库表结构不合理
8、数据库IO或CPU负载高
9、数据库参数设置不合理
10、长时间事务
11、锁竞争导致的等待

索引失效

首先,当遇到索引失效的问题时,我们通常会通过执行计划来分析数据库查询是否有效地利用了索引。执行计划可以告诉我们查询是如何执行的,是否使用了索引以及索引的效率如何。如果发现查询没有使用索引或者索引效率低下,可能是因为索引设计不合理或者数据分布不均匀导致索引失效。在这种情况下,我们可以考虑优化索引设计,重新构建索引,或者调整SQL查询语句以更好地利用索引。有时候,我们也可以通过强制指定特定的索引来引导查询优化器选择正确的索引。除了修改索引和SQL语句,还可以考虑优化查询条件,避免使用通配符开头的LIKE语句,尽量避免在WHERE子句中对字段进行函数操作,以及尽量减少JOIN操作的复杂度。这些方法都可以帮助提高查询性能和优化索引使用。如果遇到索引失效问题,还可以考虑使用数据库提供的工具和分析功能来进一步诊断和解决问题。

特殊情况-执行计划中,key有值,还是很慢怎么办?

这是在实际中遇到的一种情况。我相信大家或多或少也是遇到过这种情况的。

在执行计划中,当看到key字段有值且type为index时,很多人错误地认为这表示查询已经利用了索引。当我们查看一个SQL查询的执行计划时,经常会遇到类似以下的情况:

这个执行计划中,type=index,key=email_index 很多人会认为这表示这条SQL走了索引,但是其实这么理解是不对的。

如果是走了索引Extra中的内容应该是Using index 而不是Using where; Using index

以上的这个执行计划表明,这个SQL确实用到了email_index的这个索引树,但是他并没有直接通过索引进行匹配或者范围查询,而是扫描了整颗索引树。

所以,type=index 意味着进行了全索引扫描, 会遍历索引树来查找匹配的行,这个效率比扫表扫描快一些,但是很有限,和我们通常意义上理解的走了索引 是两回事儿。

遇到这种情况,大概率是因为没有遵守最左前缀匹配导致的索引失效了。所以需要调整查询语句,或者修改索引来解决。


多表JOIN

在SQL查询中,多表连接是导致执行速度变慢的常见原因之一。当我们需要从多个表中检索数据并将它们组合在一起时,就会使用多表连接。然而,如果不加以优化,这种连接可能会导致查询性能下降。

多表连接的执行速度变慢主要是因为数据库系统需要同时处理多个表,进行数据匹配和组合。这可能涉及大量的数据扫描、比较和排序,导致查询变得缓慢。

为了解决多表连接导致的性能问题,我们可以采取一些优化措施:

1、优化查询条件:确保在连接表时使用有效的查询条件,限制返回的数据量。这可以减少不必要的数据匹配,提高查询效率。
2、合理使用索引:为连接字段创建索引,这样可以加快数据匹配的速度。索引可以帮助数据库系统快速定位需要匹配的数据。
3、限制返回字段:只选择需要的字段,避免返回过多的数据。减少返回字段的数量可以降低数据传输和处理的负担。
4、考虑表的大小和结构:在设计数据库表结构时,考虑到表的大小和关系,可以更好地优化多表连接的性能。
5、使用适当的连接类型:根据查询需求选择合适的连接类型,如INNER JOIN、LEFT JOIN、RIGHT JOIN等。不同的连接类型会影响查询的结果和性能。

举个例子,假设我们有两个表:users和orders,我们想要查询用户及其对应的订单信息。如果我们使用以下SQL查询:

SELECT users.name, orders.order_id
FROM users
JOIN orders ON users.user_id = orders.user_id;

在这个查询中,我们通过user_id字段将users表和orders表连接起来,但如果这两个表的数据量很大,且没有合适的索引,查询可能会变得很慢。通过优化查询条件、添加索引、限制返回字段等方式,可以改善这个查询的性能,使其执行更加高效。


为什么互联网公司都不建议使用多表join?

在SQL查询中,使用JOIN操作可能会导致效率较低的主要原因在于其实现方式

MySQL通常使用嵌套循环(Nested-Loop Join)来执行关联查询。简单来说,这意味着要通过两层循环来比较两个表的记录,外循环遍历第一个表,内循环遍历第二个表,然后逐条比较记录,符合条件的结果被输出。

具体到算法实现上,MySQL主要采用了三种方式:简单嵌套循环(Simple Nested Loop)、块嵌套循环(Block Nested Loop)和索引嵌套循环(Index Nested Loop)。然而,这三种方式的效率都不是特别高。

在实际应用中,如果有两个表进行JOIN操作,复杂度最高可以达到O(n^2) 而对于三个表则是O(n^3),随着表的数量和数据量的增加,JOIN操作的效率会呈指数级下降。

值得一提的是,在MySQL 8.0中引入了哈希连接(Hash Join)算法,这种算法可以提高JOIN操作的效率。哈希连接通过构建哈希表来快速查找匹配的记录,相比于嵌套循环,可以更有效地处理JOIN操作,提升查询性能。

因此,尽管JOIN操作在处理多表关联查询时很常见,但需要注意其效率问题。为了优化查询性能,可以考虑使用适当的索引、优化查询条件、限制返回字段数量,以及利用新的算法如哈希连接来改善JOIN操作的效率。


索引基数太小不合理

什么时字段基数?

举个例子,有一个字段它一共在10万行数据里有10万个值对吧?结果呢?这个10万值,要不然就是0,要不然就是1,那么他的基数就是2,为什么?因为这个字段的值就俩选择,0和1。假设你要是针对上面说的这种字段建立索引的话,那就还不如全表扫描了,因为你的索引树里就仅仅包含0和1两种值,根本没法进行快速的二分查找,也根本就没有太大的意义了,所以这种时候,选用这种基数很低的字段放索引里意义就不大了。


查询字段太多

在数据库查询中,查询字段过多通常是因为我们错误地使用了SELECT *,导致返回了所有字段的数据。一般来说,如果查询字段少于100个,通常不会造成太大问题,除非字段数量非常庞大。在这种情况下,我们可以采取两种方法来解决。

首先,避免查询那些不必要的字段,只选择需要的少部分字段进行查询。这样可以减少数据传输和处理的负担,提高查询效率。

其次,可以考虑进行分表,即垂直分表,将数据拆分到多个表中。通过这种方式,可以将数据分散存储在不同的表中,降低单张表的数据量,提升查询性能。然而,需要注意的是,分表可能会引入多表JOIN的问题,因此在进行拆分时需要考虑数据冗余的情况。

所以,对于查询字段过多的情况,除了避免不必要字段的查询外,还可以考虑通过垂直分表的方式来优化数据存储和查询性能。在拆分表时,需谨慎考虑数据冗余和可能引发的多表JOIN问题,以达到更高效的数据查询和处理。


表中数据量太大

当单个表中的数据量超过1000万条时,通常会导致查询效率下降,即使使用了索引也可能变得比较缓慢。在这种情况下,单纯建立索引并不能完全解决问题。因此,针对大数据量表的情况,可以考虑以下几种解决方案:

1、数据归档:将历史数据移出主表,保留只保留最近半年的数据,而将半年前的数据进行归档。这样可以减少单表数据量,提升查询效率。
2、分库分表、分区:将数据拆分到多个库、多个表或者进行分区存储。通过分散数据存储的方式,可以有效降低单表数据量,提高查询性能。
3、使用第三方数据库:将数据同步到支持大规模查询的分布式数据库中,例如OceanBase、TiDB,或者存储到搜索引擎中,如Elasticsearch等。这些数据库具有更好的扩展性和处理大数据量的能力,可以提升查询效率和系统性能。

所以,针对表中数据量过大的情况,除了建立索引外,还可以通过数据归档、分库分表、分区和使用第三方数据库等方式来优化数据存储和查询性能,以应对大数据量带来的查询效率问题。


数据库连接数不够

当数据库连接数不足时,需要具体分析造成这种情况的原因。可能的原因有几个:

1、业务量过大:如果业务量巨大,单个数据库无法承载,那么最好的解决方案是进行数据库分库操作,将数据分散存储在多个库中,以减轻单库压力。
2、慢SQL或长事务:存在一些慢SQL查询或长时间运行的事务,会占用数据库连接资源,导致数据库连接数不足。这种情况下,慢SQL会占用连接资源,导致其他查询被阻塞,进而影响整体查询效率。


为什么乐观锁还会导致大量的锁耗时呢?

虽然乐观锁是不需要加锁的,通过CAS的方式进行无锁并发控制进行更新的。但是InnoDB的update语句是要加锁的。当并发冲突比较大,发生热点更新的时候,多个update语句就会排队获取锁。

而这个排队的过程就会占用数据库链接,一旦排队的事务比较多的时候,就会导致数据库连接被耗尽。

当数据库连接被耗尽时,通常是因为排队的事务过多导致的。在高并发情况下,如果排队的事务数量很大,就会耗尽数据库连接资源。

这类问题的解决思路有以下几个:
1、使用缓存进行热点数据更新,如Redis,以减轻数据库压力。
2、采用异步更新的方式,平滑处理高并发更新请求,避免峰值冲击。
3、将热点数据拆分存储到不同的库或表中,减少并发冲突。
4、合并更新请求,通过批量执行的方式降低冲突。例如,将多个增加积分的操作合并为一次性批量执行,减少数据库负担。

需要注意的是,第2和第4种方案会引入一定的延迟,将实时更新变为异步更新,可能会影响数据的实时性。而第1和第3种方案在实施过程中成本较高,但相对更完整。

根据实际业务场景,选择合适的解决方案非常重要。在某些情况下,如我们的业务场景,选择第4种方案,即合并更新操作并批量执行,可以有效降低数据库连接压力。举例来说,如果需要给100个用户增加积分,可以将这些操作合并并在一定时间间隔内批量执行,以减少数据库负担。


数据库表结构不合理

当数据库表结构不合理时,这也是造成性能问题的关键原因之一。例如,某些字段存储了过长的内容,或者缺乏合理的冗余导致需要频繁进行多表关联查询。解决这类问题的思路通常是进行数据库重构或者考虑分表操作。


数据库IO或者CPU比较高

另外,数据库高IO或CPU占用率也是常见的问题。当数据库整体IO或CPU负载过高时,查询速度可能会下降,因此需要分析背后的原因并采取相应的解决方案。


存在长事务

长事务和慢SQL问题类似,都会占用数据库连接,导致其他请求需要等待。


锁竞争导致的等待

在数据库中,锁竞争也会导致等待。当多个并发请求争夺共享资源时,会导致锁等待,进而增加执行时间,使SQL变慢。这种情况也会类似于CPU被打满的问题。


数据库参数不合理

针对具体业务场景,适当调整数据库参数可以显著提升SQL效率。例如,调整内存大小、缓存大小、线程池大小等参数都可能对数据库性能产生影响。

编辑:三两肉
来源:码上遇见你

相关文章:

总结:SQL查询变慢,常见原因分析!

文章目录 引言SQL查询慢原因索引失效特殊情况-执行计划中,key有值,还是很慢怎么办? 多表JOIN为什么互联网公司都不建议使用多表join? 索引基数太小不合理查询字段太多表中数据量太大数据库连接数不够为什么乐观锁还会导致大量的锁…...

基于webrtc实现音视频通信

与传统通信方式不同,p2p通信的实现过程不依赖于中间服务器的信息收发,直接通过信令等完成通信过程的建立; 通过websocket实现信令服务器的建立,而通过信令来确定通信双方; webrtc通过 sdp协议来完善通信双方间协议的…...

【多版本并发控制(MVCC)】

并发事务问题: MySQL隔离级别-未提交读,提交读,可重复读,序列化 隔离级别对于并发事务的解决情况 隔离级别脏读不可重复读幻读未提交读不可不可不可读已提交可不可不可可重复读 (默认)可可不可串行化&…...

常见漏洞及webshell工具的流量特征

常见攻击的流量特征 信息泄露 请求/路径中,包含 特殊文件 或 路径;响应包中,包含敏感信息(如,数据结构,用户信息,网络结构等) 弱口令爆破 非常规流量:短时间内大量数据…...

python学习-怎么在Pycharm写代码

打开Pycharm,点击文件-新建项目 2.选择pure python-点击箭头 展开 3.选择 Existing interpreter 如果 Existing interpreter 下没有相关环境 (1)点击**…** (2)选择python的安装路径 4.可修改文件名称-点击创建 …...

牛客周赛63(C++实现)

🌈个人主页:Yui_ 🌈Linux专栏:Linux 🌈C语言笔记专栏:C语言笔记 🌈数据结构专栏:数据结构 🌈C专栏:C 文章目录 1.小红的好数1.1 题目描述1.2 思路1.3 代码 2.…...

高级英语1第四版教材全解pdf课后答案+课文翻译张汉熙

《高级英语1》是张汉熙教授编著的一本英语教材,广泛用于国内高校英语专业高年级学生的教学。这本书以提高学生的英语综合能力为目标,注重语言知识的系统性和实用性,同时强调跨文化交际能力的培养。书中选材丰富,涵盖了文学、历史、…...

视频去水印软件3款推荐:好用的去水印软件分享!

在处理视频素材时,水印往往是一个令人头疼的问题。幸运的是,市面上有许多优秀的视频编辑软件能够帮助我们快速、有效地去除水印。今天,我将为大家推荐三款功能强大的视频去水印软件:影忆、Final Cut Pro X以及Adobe Premiere Pro&…...

perl文件测试操作符及其意义

perl文件测试操作符及其意义 文件测试操作符意义-r文件或目录,对目前(有效的)用户或组来说是可读的-w文件或目录,对目前(有效的)用户或组来说是可写的-x文件或目录,对目前(有效的&a…...

NC 单据模板自定义项 设置参照(自定义参照)

NC 单据模板自定义项 设置参照(自定义参照) 如图下图,NC 单据模板自定义项 设置参照: 1、选择需要设置参照的自定义字段,选择高级属性页签,在类型设置中,数据类型选择参照信息,即bd…...

Element-ui官方示例(Popover 弹出框)

Element-ui官方示例(Popover 弹出框),好用的弹出框。 使用 vue-cli3 我们为新版的 vue-cli 准备了相应的​Element 插件​,你可以用它们快速地搭建一个基于 Element 的项目。 使用 Starter Kit 我们提供了通用的项目模版&#…...

Bootstrap 5 练习 - 显示工具提示

文章目录 引言准备工作创建HTML文件导入Bootstrap 5框架编写页面代码编写JavaScript脚本浏览网页注意事项结束语 引言 大家好,今天我们将一起学习如何在Bootstrap 5中创建一个简单的工具提示(Tooltip)。工具提示是一个非常实用的用户界面元素…...

【p2p、分布式,区块链笔记 Torrent】: WebTorrent GitTorrent bittorrent-dht

bittorrent-dht模块 BitTorrent DHT 通过 DHT 网络广播值,允许其他用户通过 DHT 来发现和获取这些数据。 1. 导入依赖 var DHT require(bittorrent-dht)2. 创建实例 var dht new DHT({bootstrap: config.dht.bootstrap }) dht.listen(config.dht.listen)new D…...

【Next.js 项目实战系列】05-删除 Issue

原文链接 CSDN 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话,给我的库点个star,关注一下吧 上一篇【Next.js 项目实战系列】04-修改 Issue 删除 Issue 添加删除 Button​ 本节代码链接 这里我们主要关注布局…...

Springboot api http并发测试请求

pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> 线程发起请求 package com.example.demo;import org.springframework.http.HttpEntity; import org…...

Qt的websocket客户端和服务器测试(非安全版本)

测试内容&#xff1a; 客户端&#xff1a; 1 连接服务器 2 发送数据 3 处理错误信号 4 监听断开信号 5 接收服务器的数据 服务器&#xff1a; 1 监听等待客户端连接 2 向指定的客户端发送数据 4 监听断开信号 5 接收客户端的数据 测试界面 工程文件.pro添加的内容&#xff1a;…...

Prometheus运维监控平台之监控指标注册到consul脚本开发、自定义监控项采集配置调试(三)

系列文章目录 运维监控平台搭建 运维监控平台监控标签 golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置V1版本 文章目录 系列文章目录目的一、监控指标注册到consul的golang脚本开发1、修改settings.yaml文件2、修改config/ocnsul,go文件3、修改core/consul…...

C语言——数组

1.数组的概念 数组是一组相同类型元素的集合&#xff1b; 数组中可以存放1个或多个元素&#xff0c;但数组元素个数不能为0。 同时数组可以分为一维数组和多维数组&#xff0c;多维数组一般常见 是二维数组。 2.一维数组的创建和初始化 一维数组的创建的基本语法&#xff1a; …...

MySQL-09.DDL-表结构操作-查询修改删除

一.查询 二.修改 三.删除 -- DDL&#xff1a;查看表结构 -- 查看&#xff1a;当前数据库下的表show tables ;-- 查看&#xff1a;查看指定的表结构 desc tb_emp;-- 查看&#xff1a;数据库的建表语句 show create table tb_emp;-- DDL:修改表结构 -- 修改&#xff1a;为表tb…...

WileyNJDv5_Template模板无法编译生成pdf文件

文章目录 问题解决办法结果 问题 使用WileyNJDv5_Template模板时&#xff0c;修改tex文件里的内容&#xff0c;按F6编译后&#xff0c;并没有报错&#xff0c;但是编辑后的pdf文件没有生成&#xff0c;因为看文件夹里的pdf文件日期还是以前的日期&#xff0c;所以是旧版的pdf文…...

亿配芯城(ICGOODFIND)教你外贸(海外)推广电子元器件芯片的专用词语

在电子元器件行业&#xff0c;海外推广是企业拓展市场、提升竞争力的重要手段。而在海外推广过程中&#xff0c;恰当运用专用词语能够准确传达产品信息、吸引客户关注&#xff0c;提升推广效果。本文将详细介绍亿配芯城&#xff08;ICGOODFIND&#xff09;电子元器件海外推广中…...

windows和linux的一些使用问题一一记录

文章目录 windows 11 激活wsl文件共享命令互通wslg网络 Hyper-V双系统遇到再记录……… windows 11 激活 然后执行 slmgr /skms kms.03k.org slmgr /atowsl 卡死打开任务管理关闭下就行了 wsl --list -v # 安装的 wsl --list --online #可以安装的wsl -d kali-linux # 启…...

排序算法上——插入,希尔,选择,堆排序

前言&#xff1a; 常见排序方法如下&#xff1a; 本篇将介绍4种排序方法&#xff0c;分别为插入排序&#xff0c;希尔排序&#xff0c;选择排序&#xff0c;堆排序&#xff0c;并分别举例与讲解。 一. 插入排序 1.1 含义与动图分析 插入排序的思想是在有序区间的下一个位置…...

Mycat 详细介绍及入门实战,解决数据库性能问题

一、基本原理 1、数据分片 &#xff08;1&#xff09;、水平分片 Mycat 将一个大表的数据按照一定的规则拆分成多个小表&#xff0c;分布在不同的数据库节点上。例如&#xff0c;可以根据某个字段的值进行哈希取模&#xff0c;将数据均匀的分布到不同的节点上。 这样做的好处…...

FFmpeg源码:avformat_new_stream函数分析

一、avformat_new_stream函数的声明 avformat_new_stream函数定义在FFmpeg源码&#xff08;本文演示用的FFmpeg源码版本为7.0.1&#xff09;的头文件libavformat/avformat.h中&#xff1a; /*** Add a new stream to a media file.** When demuxing, it is called by the dem…...

【java】深入解析Lambda表达式

Lambda表达式是Java 8引入的一项重要特性&#xff0c;它提供了一种简洁的方式来实现函数式编程。Lambda表达式的使用广泛而且灵活&#xff0c;可以简化代码并提高可读性。本篇文章将深入解析Lambda表达式&#xff0c;包括使用场景、基础学习、代码案例、实现方法和注意事项等方…...

Chromium html<img>对应c++接口定义

<img src"tulip.jpg" alt"上海鲜花港 - 郁金香" /> 1、html_tag_names.json5中接口定义&#xff1a; &#xff08;third_party\blink\renderer\core\html\html_tag_names.json5&#xff09; {name: "img",constructorNeedsCreateElementF…...

卸载Python

1、查看安装框架位置并删除 Sudo rm -rf /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8 2、查看应用并删除 在 /Applications/Python 3.x 看是否存在&#xff0c;如果存在并删除。 3、删除软连接 ls -l /usr/bin/py* 或 ls -…...

算法剖析:二分查找

文章目录 前言二分查找模板朴素模板左右查找模板 一、二分查找二、 在排序数组中查找元素的第一个和最后一个位置三、搜索插入位置四、x 的平方根五、山脉数组的峰顶索引六、寻找峰值七、寻找旋转排序数组中的最小值八、 点名总结 前言 二分查找是一种高效的查找算法&#xff…...

Invoke 和 InvokeRequired以及他们两个的区别

在.NET中&#xff0c;Invoke和InvokeRequired是Windows Forms编程中用于确保线程安全的关键方法和属性。它们通常用在多线程环境中&#xff0c;以确保UI控件的更新操作在创建控件的线程上执行&#xff0c;避免因跨线程操作导致的异常。 InvokeRequired 属性 InvokeRequired属…...