3种SQL语句优化方法,测试人必知必会!

关于SQL语句的优化,本质上就是尽量降低SQL语句的执行时间,对于如何降低SQL语句的执行时间,可以从以下几个方面入手。

一、降低SQL语句执行时的资源消耗

这是我们在数据库性能调优中常用的方法,该方法以分析SQL语句的执行计划为切入点,核心思路是找到执行计划中开销较高的操作,通过改写SQL语句或改变表访问方式调整执行计划,从而达到降低SQL语句执行消耗,缩短执行时间的目的。

对于改变表访问方式,常见的手段是使用索引替代开销较高的全表扫描,但这种方式不是万能的,是有一定的使用前提的,有时候,滥用索引反而会带来较高的性能开销。

以下列举一些适合采用访问索引的方式替代原有操作的案例。

1. 使用索引替代全表扫描

如果查询结果集只占表中的一小部分数据,这时,可以采用索引访问的方式替代全表扫描,即使不能达到索引覆盖而产生回表操作,其开销也小于采用全表扫描操作。

例如,使用Oracle数据库存储,一个用户信息表

user(userid,username,sex,tel,code),code列表示用户的社保号信息,系统运行之初允许社保号信息为非必填项,这就导致少部分code列的值为null,为了提高对code列检索的效率,我们为code列创建了普通B树索引inx_code(code),要查询所有未提供社保号的那部分用户信息,之后系统为这部分用户发送信息,提示补全社保号信息,语句如下:

select * from user where code is null;

语句执行后,用时20秒左右,user表中存在50万条左右的用户记录,返回的未提供社保号的用户记录有5000条左右。

通过分析执行计划,在查询执行时采用了全表扫描方式,这是造成查询执行时间较长的主要原因。

对于B树单列索引,null值将使得索引失效,所以优化器采用了全表扫描方式。

该查询实际返回记录5000条左右,表中共有记录50万条左右,实际返回的记录只占表总记录的1%,这时,可以采取使用索引扫描替代全表扫描。

如何使得包含null值的列在检索时可以使用索引呢,这就需要将基于B树的单列索引改为复合索引,将原有索引修改为inx_code(code,0),再次执行查询,对user表的访问方式由全表扫描改为索引范围扫描,执行时间降至1秒之下。

现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:691998057【暗号:csdn999】

2. 利用索引的有序性消除排序操作

在对数据库的访问中,排序是一种开销较搞的操作,数据库为了完成排序操作,需要扫描表中的所有记录,之后采取相应的算法对记录进行排序。

如果表中的记录随系统的运行累积增加,那么排序操作的执行开销会逐渐变大,执行时间会越来越长。

索引是有序的,因为相应的索引键值已经事先按一定规则完成排序,如果SQL语句中需要按表中的某列进行排序,此时,可以为该列创建索引,从而达到通过索引扫描代替完成排序需要的全表扫描,达到降低访问开销,缩短执行时间的目的。

例如,在MySQL8.0数据库中,如果需要对多个列进行排序,且排序顺序有升有降,即:order by col1,col2 desc,此时,可以为两个排序列创建一个复合降序索引idx_col1_col2(c1,c2 desc)

3. 利用索引改变表关联方式

在执行表关联查询操作时,数据库的优化器可能选择了不合理的表关联方式,使得表关联查询开销较高,耗时较长。

例如,PostgreSQL数据库中有userureorg三个表,分别存储系统用户信息、已完成认证的用户信息和相应的组织信息。有如下的查询语句:select *  

from user join ure on user.id=ure.id join on org on ure.oid=org.oid

where org.pcode=’12012’

order by ure.update;

该查询的执行计划如下图所示:

查询执行用时32毫秒,开销为2206。

通过执行计划我们发现,userureorg三表关联均采用了Hash Join的关联方式,这种关联方式是最优的吗?

分析表连接方式,org表是第一个关联的驱动表,该表过滤后的结果集只有24条记录,结果集很小,所以,可以将org表与user表的连接方式调整为嵌套循环连接方式。

此外,对org表的访问采用了全表扫描,可将其调整为索引扫描。

为查询org表的where条件列pcode列创建索引,同时为作为嵌套循环连接的被驱动表user表的关联条件列oid列创建索引,本次调优后的执行计划如下图所示。

改变org表与user表的连接方式后,执行时间降低为4.85ms,执行开销降低到273。

进一步分析调优后的执行计划,org表与user表连接后的结果集只有47条记录,该结果集与ure表的连接方式仍可以调整为嵌套循环连接,以该结果集作为驱动表,ure表作为被驱动表。为达到该目的,为ure表的连接条件列id设置索引即可。

最终的执行计划如下图所示。

由此可见,将表连接方式全部由Hash连接调整为嵌套循环连接后,执行时间最终降至1ms,执行开销降至30。

二、并行执行SQL语句

这种方式是通过增加额外的资源消耗来换取SQL执行时间的缩短,其意义类似于代码优化中的“以空间换时间”的策略。

增加的额外资源主要是指数据库服务器的处理器(CPU)、内存、I/O等硬件资源。

例如:在Oracle数据库中,对于一个查询操作,如果其所作的工作可以分割成多个互不相关的部分,则该查询可以由多个进程并发执行。可以并行执行的查询操作主要有全表扫描、快速索引全扫描、分区索引范围扫描、以及需要执行全表扫描完成的表连接。

三、避免不必要的资源争用导致SQL执行效率下降

有些SQL语句,其执行时间不定,时快时慢,这些语句的执行计划自身未存在问题。导致语句执行效率差的原因是语句执行时,数据库服务器在执行其他消耗资源的操作,出现资源争用的情况。

例如:某系统每日凌晨定时执行统计信息收集工作,如果这时对系统执行性能测试,涉及对该数据的查询操作将受到影响,导致性能测试结果不准确。因此,性能测试需要避开数据库执行统计信息收集的时间。

以上对SQL语句的优化方法做了简要的介绍,下面对SQL语句的优化步骤和方法做一个说明和总结。

  • 1. 找到执行时间较长、消耗资源较多的SQL语句。例如:MySQL数据库可从慢查询日志中获取,Oracle数据库可查看AWR报告。

  • 2. 分析以上获取的性能较差的SQL语句的执行计划,找到执行计划中开销较高的部分,评估执行计划是否合理,是否需要调整。

  • 3. 对于执行计划中开销较高的部分,采取相应的措施降低执行开销,缩短执行时间,例如如下方式:

  • (1)如果是统计信息不准确导致生成了错误的执行计划,需要首先重新收集统计信息;

  • (2)如果是SQL语句编写存在问题,可以在不改变业务逻辑的前提下对SQL语句进行适当的改写;

  • (3)对于不必要的全表扫描或排序,可以通过创建合适索引消除全表扫描和排序;

  • (4)如果因为某些原因导致SQL语句的执行计划不稳定,在条件允许的情况下,使用提示器(Hint)固定SQL语句的执行计划;

  • (5)如果因为表或索引本身设置不合理,导致执行开销较高,用时较长,则应该对表或索引重新设计,例如:表中记录过大,超过亿级,此时应考虑分表分库;

  • (6)对于具备并行执行的部分,考虑采用并行执行的方式;

  • (7)如果是业务设计不合理导致SQL语句执行效率低下,应考虑修改业务逻辑。

END

下面是配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

最后: 可以在公众号:程序员小濠 ! 免费领取一份216页软件测试工程师面试宝典文档资料。以及相对应的视频学习教程免费分享!,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。

如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/703987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python实用技巧:处理JSON文件写入换行问题

Python实用技巧:处理JSON文件写入换行问题 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 👈 希望得到您的订阅…

linux中将普通用户添加sudo权限

1.登录root权限账号,编辑/etc/sudoers文件 2.找到"root ALL(ALL) ALL",并在下面添加普通用户 格式:username ALL(ALL) ALL vim /etc/sudoers ## Next comes the main part: which users can run what software …

CMake和VsCode调试的使用

目录 CMake使用 CMake下载 创建系统文件目录 MakeList编写规范 VsCode启动调试 添加配置文件 添加断点,启动调试 CMake使用 CMake下载 输入指令 sudo apt install cmake 安装cmake,使用 cmake -version可查看cmake的版本信息 创建系统文件目…

土耳其商务团一行莅临优积科技考察交流

7月31日土耳其商务代表Emre Arif Parlak等一行三人莅临优积科技考察交流,公司CEO刘其东携团队成员热情接待并深入交流。 商务团首先参观了我司产品生产基地,详细了解了钢结构模块的生产加工工艺流程和质量控制体系。随后参观了我司模块化学校样板房、模块…

Git+py+ipynb Usage

0.default config ssh-keygen -t rsa #之后一路回车,当前目录.ssh/下产生公私钥 cat ~/.ssh/id_rsa.pub #复制公钥到账号 git config --global user.email account_email git config --global user.name account_namebug of ipynb TqdmWarning: IProgress not found. Please …

一文1400字使用Jmeter进行http接口测试【建议收藏】

前言: 本文主要针对http接口进行测试,使用Jmeter工具实现。Jmter工具设计之初是用于做性能测试的,它在实现对各种接口的调用方面已经做的比较成熟,因此,本次直接使用Jmeter工具来完成对Http接口的测试。 一、开发接口…

【JavaSE】集合框架

目录 程序场景分析 Java集合框架包含的内容List接口ArrayListLinkedListList接口的常用方法ArrayList案例背景分析代码示例扩展以下功能代码示例 LinkedList案例背景分析代码示例LinkedList的特殊方法 ArrayList与LinkedList对比 Set接口HashSet 集合的特点常用方法案例背景分析…

[c 语言] 大端,小端;网络序,主机序

在网络编程中,特别是底层网卡驱动开发时,常常遇到字节序问题。字节序指的是多字节数据类型在内存中存放的顺序,高位保存在低地址还是高地址,以此来划分大端还是小端。 1 大端和小端 大端和小端指的是 cpu 的属性,常见…

Vulhub 靶场训练 DC-9解析

一、搭建环境 kali的IP地址是:192.168.200.14 DC-9的IP地址暂时未知 二、信息收集 1、探索同网段下存活的主机 arp-scan -l #2、探索开放的端口 开启端口有:80和22端口 3、目录扫描 访问80 端口显示的主页面 分别点击其他几个页面 可以看到是用户…

SpringBoot源码解读与原理分析(三十四)SpringBoot整合JDBC(三)声明式事务的传播行为控制

文章目录 前言10.5 声明式事务的传播行为控制10.5.1 修改测试代码(1)新建一个Service类,并引用UserService(2)修改主启动类 10.5.2 PROPAGATION_REQUIRED10.5.2.1 tm.getTransaction(1)获取事务…

用于自监督视觉预训练的屏蔽特征预测

Masked Feature Prediction for Self-Supervised Visual Pre-Training 一、摘要 提出了用于视频模型自监督预训练的掩模特征预测(MaskFeat)。首先随机屏蔽输入序列的一部分,然后预测屏蔽区域的特征。研究了五种不同类型的特征,发…

遥感、航拍、影像等用于深度学习的数据集集合

遥感图像的纹理特征异常繁杂,地貌类型多变,人工提取往往存在特征提取困难和特征提取不准确的问题,同时,在这个过程中还会耗费海量的人力物力。随着计算力的突破、数据洪流的暴发和算法的不断创新,在具有鲜明“大数据”…

ffmpeg的pcm、yuv小知识点

ffmpeg的pcm、yuv小知识点 pcm、yuv保存调用,写个通用工具方法,平时快速保存,和调用方便查看自己bug ffmpeg的AVFrame存储 yuv 调用方法 保存方法 void save_yuv420p_file(unsigned char *y_buf , unsigned char *u_buf,unsigned char *…

git commit 后,本地远端都没有记录,消失不见

今天git commit 之后发现远端没有记录,本地没有最新代码记录 git commit 后,提交记录会消失不见的原因可能是: git只git commit了,没有push到远程分支,切换到其他分支时丢失。而且看不到提交记录,和找不到…

2024.2.21 模拟实现 RabbitMQ —— 实现转发规则

目录 需求分析 直接交换机(Direct ) 主题交换机(Topic ) 扇出交换机(Fanout ) Topic 交换机转发规则 routingKey 组成 bindingKey 组成 匹配规则 情况一 情况二 情况三 实现 Router 类 校验 b…

Spring Boot application.properties和application.yml文件的配置

在Spring Boot中,application.properties 和 application.yml 文件用于配置应用程序的各个方面,如服务器端口、数据库连接、日志级别等。这两个文件是Spring Boot的配置文件,位于 src/main/resources 目录下。 application.properties 示例 …

vue中动态表格中文校验,但是中文的参数无法获取

场景: 解决方案: 因为上述的正则表达式后,使用搜狗输入法没有问题,但采用微软自带输入法后,会存在输入数字及英文时为正常,切换为汉字后,会存在吞并当前光标前的字符。具体吞并个数和输入法中有…

Unity发布webgl获取浏览器的URL

Unity发布webgl获取浏览器的URL Unity发布webgl之后获取浏览器的url 在unity中创建文件夹Plugins,然后添加添加文件UnityGetBrowserURL.jslib var GetUrlFunc {//获取地址栏的URLStringReturnValueFunction: function () {var returnStr window.top.location.hre…

SpringBoot3整合Swagger3,访问出现404错误问题(未解决)

秉承着能用就用新的的理念,在JDK、SpringBoot、SpringCloud版本的兼容性下,选择了Java17、SpringBoot3.0.2整合Swagger3。 代码编译一切正常,Swagger的Bean也能加载,到了最后访问前端页面swagger-ui的时候出现404。 根据网上资料…

Oracle ADG相关介绍

文章目录 一、ADG原理1、ADG介绍2、ADG搭建流程 二、ADG相关参数三、增量修复 一、ADG原理 1、ADG介绍 Oracle ADG(Advanced Data Guard)是Oracle数据库的一项高可用和灾难恢复技术,它通过将数据保持在物理备库中来提供数据保护和容灾能力。…