首页 > 数据库 >Sql优化技巧总结(面试必刷!!!)

Sql优化技巧总结(面试必刷!!!)

时间:2024-11-13 10:18:47浏览次数:3  
标签:Name 索引 使用 面试 User Sql 必刷 ID Select

摘要

        近段时间,面试官关于Sql优化的提问已经越来越多了,Sql优化可以说是已经成为了面试必备技能之一。本文从Sql语句、硬件设备以及Java程序三个方面详细的讲解关于Sql优化的技巧。

目录

摘要

一、Sql语句优化

1、避免使用 Select *

总结

2、使用(创建)索引

2.1、不能在索引上使用计算操作

2.2、不能在索引上使用函数

2.3、索引不是多多益善

总结

3、用 UNION All 避免 UNION

4、EXISTS() 和 IN()

5、使用连接查询代替子查询

6、多使用 limt/rownum 这种限制条目数的条件

7、提高group by having的运行效率

8、使用 UNION All 代替 or

9、合理的定义字段类型

二、设备硬件优化

三、代码块优化(Java)

1、批量插入

2、使用连接池技术

3、利用缓存机制

4、利用异步处理


一、Sql语句优化

1、避免使用 Select *

        举个例子如下:

        Select * From User Where rownum = 1

       在写Sql的时候,我们为了方便会使用以上方式查询(rownum = 1 表示只取一条),但是直接使用Select * 会使索引无法产生作用。

        举个例子,user表中有ID,Name,Age这三个字段。

Select ID From User Where ID = 1

        此时ID为主键有索引的存在,如果 那么利用索引效率就会大大提高,但是如果还需要其他数据,例如:

Select ID,Name From User Where ID = 1

        这时由于只有ID字段有建立索引,而获取Name字段则需要回到表内进行全表扫描,从而导致效率很低。

总结

        Select * 不会走覆盖索引,会进行大量的回表操作,故而影响Sql运行效率。

2、使用(创建)索引

        众所周知使用数据库的索引机制会大大提升Sql运行效率,那么如何正确使用索引!

2.1、不能在索引上使用计算操作

        举个例子:

        Select Name From User Where ID + 1= 9

        在索引上使用计算操作时就会使索引失效!所以非必要尽量避免,如果业务需要一定需要在索引上计算,那么可以换一个写法,比如:

Select Name From User Where ID = 9 - 1

        此时索引便不会失效,你可能会觉得(9-1)有什么意义呢?我直接写8不好吗?但是实际业务中对于单表的操作一般很少,针对于业务需要进行多表联查。比如之前接触的医院HIS系统,多时能有十几张表,这个时候就可以将 “9”  或者  “1”  替换成其他表的某两个字段,从而达到避免在索引上计算的效果。

2.2、不能在索引上使用函数

        因为索引是在基于索引列的原始值建立的,而不是通过使用函数后的值建立的,所以在索引上使用函数会使索引失效。例如:

Select Name From User Where next(ID)

        所以要尽量避免在索引上使用函数。但是如果非要使用,且使用频率较高调用函数固定的话可以考虑建立函数索引,需要的话去单独了解。

2.3、索引不是多多益善

        不知道大家有没有这种疑问,如果索引很方便,那么我给所有字段都加上索引那么Select * 不是也可以大大提高运行效率呢?

        这里就需要知道索引是如何建立产生的,为什么使用它会变快,这个内容比较多就不再这里一一赘述。简单来说就是索引建立也是需要时间的,你插入或者修改的时候导致索引变更都是需要耗费时间的,这个本身也是需要耗费时间影响效率的,所以索引不是多多益善的。

总结

        尽量不要对索引列进行操作,并且索引的建立也不是越多越好。

3、用 UNION All 避免 UNION

        UNION All 与 UNION 的区别在于,UNION 会自动去掉重复内容。所以业务中没有要求不能出现重复数据时,尽量使用UNION All。UNION 去重时会遍历、排序和比较从而影响效率。

4、EXISTS() 和 IN()

        这两个子句的功能都是差不多的,那么什么情况要选择要选择怎么样的子句呢?这里就涉及到另外一个优化方式,小表驱动大表。

先说结论:

        (1)、当子句中子表的数据量小于主表的数据量时,使用IN()

        (2)、当子句中子表的数据量大于主表的数据量时,使用EXISTS()

        (3)、当子表与主表数据量差不多时,两个子句的执行效率是差不多的

举个例子,假设 Person表中数据有10000条数据,User表中有1000条数据:

1、Select Name From User

        Where Name IN(Select Name From Person)

2、Select Name From User u

        Where EXISTS(Select 1 From Person Where Name = u.Name)

         使用 IN() 子句时,是User表驱动Person表,先查出Person表的数据存入内存中,再去查User表中的数据,这样子执行最低效率是Person.length * User.length。
        而使用Exists() 子句时,它并不关心对于Person表中数据的结果集,只关心存不存在。并且首先针对User表执行查询,所以Exists() 子句最多只会执行User.length次。这样子执行最低效率是User.length * User.length。

        综上所述,当Where子句中的子表数据相较于主表较小时,使用IN() 子句的话效率更高。想要了解更多,后续可以在单开一章,这里就不一一赘述了。

5、使用连接查询代替子查询

        通过使用连接查询和子查询的方式,都能达到查询多表关联数据的目的。

举个例子:

子查询:

        Select  P.Name,(Select DepNa From Dept Where P.ID = Pid) From Person P

连接:

        Select  

                P.Name,D.DepNa

        From

                Person P

                Left Join Dept D on P.ID = D.Pid

         通过以上语句进行子查询时,针对于Person表中的每一条数据都需要去Dept表中去进行遍历查找,所以除了对于Person的遍历外,还需要多次访问Dept表进行遍历时间复杂度较高。

        而使用Left Join进行关联时,会先将Person表与Dept表均遍历一次关联起来,而不会多次对Dept表进行遍历效率大大提高。

        综上所述,如果使用连接和子查询都可以达到业务需求,那么优先考虑使用连接的方式,效率会更高。

6、多使用 limt/rownum 这种限制条目数的条件

        假如现在业务需要获取到某用户的最新的订单,举个例子:

Select * From Order Where User_ID = 111  And  Order By Insert_Time Desc

         通过以上方式获取Order表中D为111用户的所有订单,并根据插入时间排序从而获取最新的订单。

Select * From Order Where User_ID = 111  And  Order By Insert_Time Desc And Rownum = 1

        通过增加限制结果集的关键字,从而只获取到需要的一条数据,进而大大提高Sql语句的运行效率。

7、提高group by having的运行效率

        group by和having配合使用,可以对结果集进行分组和过滤。举个例子:

Select User_Name,User_ID From Order 

Group By User_ID

Having User_ID < 100

        根据用户进行分组并筛选出ID小于100的用户。以上Sql可以实现功能但是还有优化空间。在运行此Sql时,会先查询出所有的订单号,然后再进行分组和过滤。这个时候就要考虑Having的过滤可不可以再查询时实现。举个例子:

Select User_Name,User_ID From Order 

Where User_ID < 100

Group By User_ID

        此时就会在查询时就会过滤结果集,使得分组时的数据量减少从而提高效率。

8、使用 UNION All 代替 or

Sql1使用or: 

        Select User_Name From User  Where User_ID = 10081 or Salary = 10000.00

Sql2使用union all :

        Select User_Name From User  Where User_ID = 10081

        Union all

        Select User_Name From User  Where Salary = 10000.00

        使用or时可能会导致索引失效从而进行全表扫描,运行Sql语句1时如果走了User_ID的索引但是Salary还要进行全表扫描。不如使用Sql语句2直接一次全表扫描获得结果。

9、合理的定义字段类型

        在数据库中定义字符串类型的字段时。如果不确定该字段的长度并且长度也并不固定时,选择varchar要优于char。

        char是固定长度的字符串,假设定义长度为255,但是实际长度为25该字段占用空间依旧为255。而varchar是可变长度的字符串,只会定义最大长度,会根据存储内容来变化长度。从而节省空间。而且对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

我们在选择字段类型时,应该遵循这样的原则:

1、能用数字类型,就不用字符串,因为字符的处理往往比数字要慢。

2、尽可能使用小的类型,比如:用bit存布尔值,用tinyint存枚举值等。

3、长度固定的字符串字段,用char类型。

4、长度可变的字符串字段,用varchar类型。

5、金额字段用decimal,避免精度丢失问题。

等等。。。

二、设备硬件优化

        在硬件层面,CPU和内存的性能对SQL执行速度有直接影响。如果CPU或内存资源不足,可能导致SQL执行卡顿或延迟。在这种情况下,可以考虑升级硬件设备,增加CPU核数或扩展内存容量,以提高系统性能。例如:

  1. 升级CPU:选择高性能的CPU,特别是多核处理器,以提高并发处理能力。较高的CPU频率和更多的核心数可以加快SQL查询和计算速度。
  2. 增加内存容量:增加内存可以减少频繁的磁盘访问,提高缓存命中率,从而加快数据读取和写入速度。
  3. 选择高速存储设备:使用固态硬盘(SSD)替代传统机械硬盘可以大幅提升IO性能,加快数据的读写速度。
  4. 提高网络带宽:优化数据库服务器与客户端之间的网络连接,确保网络带宽充足,减少网络延迟对数据库操作的影响。
  5. 调整操作系统参数:针对数据库工作特性,调整操作系统的参数如文件描述符、最大进程数等,以提高数据库性能。

三、代码块优化(Java)

1、批量插入

        当需要往某张表中批量插入数据时:

public void addUser(List<User> userList ) {
        for (User user : userList) {
            userMapper.insert(user);
        }
    }

        使用以上代码可以实现功能,但是由于在Java程序中每次运行Sql语句都需要与数据库建立连接,所以当数据量过大时使用此方法会增加不需要的性能消耗。可以自定义一个的批量插入的方法来实现功能。

userMapper.insertAll(userList);

<insert id="insertAll">
    INSERT INTO orders (user_id, user_name, salary)
    VALUES
    <foreach collection="list" item="user" separator=",">
        (#{user.user_id}, #{user.user_name}, #{user.salary})
    </foreach>
</insert>

        这样的话只需要与数据库产生一次连接通信就可以实现批量插入的功能,从而大大提高效率。但是如果表字段过多且数据量过大,那么可能会导致内存溢出。这是因为批量插入时,所有数据都需要加载到内存中,然后一次性发送给数据库。如果数据量非常大,可能会超出 JVM 的堆内存限制,从而导致内存溢出。所以可以对每一次通信的数据量进行限制例如每插入600条数据与数据库进行一次连接通信。

2、使用连接池技术

        频繁地创建和关闭数据库连接,会增加系统开销。如果使用数据库连接池可以管理连接,提高连接的复用性和性能。以下配置连接池的示例:

spring:
  datasource:
    url: jdbc:oracle:thin:@ IP:port:bsrun
    username: 
    password: 
    driver-class-name: oracle.jdbc.OracleDriver
    druid:
      # 连接池的配置信息
      # 初始化大小,最小,最大
      initial-size: 5
      min-idle: 5
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000

3、利用缓存机制

        合理的利用缓存机制也可以避免与数据库产生通信连接,对于一些固定的或者很少调休的数据,可以在进行查询之后保存起来。再没有执行Insert、Update以及Delete的情况下,在每次第一次查询过后储存起来,之后再查询就从缓存中获取。

4、利用异步处理

        对于一些耗时的Sql语句,可以使用异步方法去执行。将数据库操作放到后台线程中执行,提高系统的并发能力和性能。

标签:Name,索引,使用,面试,User,Sql,必刷,ID,Select
From: https://blog.csdn.net/qq_65225921/article/details/142789946

相关文章

  • 解决高版本laravel/framework中SQLServer2008分页报错问题
    前提:laravel自6.0后就明确了支持的SQLServer版本最低为2017,而SQLServer是在2012版本后,引入的offset语法来实现分页,在此之前只能使用ROW_NUMBER()函数来完成分页。问题:生产环境的SQLServer由于历史原因,仍旧使用的2008版本,自然是不支持offset语法的,而新建项目使用的laravel版本......
  • Linux内存管理,它的价值?面试被问过吗?
    Linux内核的内存管理是操作系统最基础且关键的部分之一。它直接影响系统性能、资源分配的效率和多任务管理的稳定性。掌握Linux内核的内存管理,不仅能够帮助我们理解操作系统如何调度资源,还能优化应用程序的性能。在面试中,内存管理常常是考察系统设计、操作系统基础和调优......
  • 启动mysql报错“服务没有响应控制功能”
    启动mysql服务器报错,如图: 解决方案:1、查看path环境变量配置正确2、查看初始化配置文件正确[mysqld]#设置3306端口port=3306#设置mysql的安装目录basedir=D:\\mysql-8.0.40-winx64#设置mysql数据库的数据的存放目录datadir=D:\\mysql-8.0.40-winx64\\data#允......
  • Freesql、SqlSugar测试有感
    突然心血来潮测试了一下Freesql和SqlSugar的批量插入和批量更新性能,一搜测评一大堆,但是没找到自己想要的结果,自己动手测试一下基本的批量插入和批量更新性能。废话不多说直接贴代码1usingFreeSql;2usingFreeSql.DataAnnotations;3usingSqlSugar;45namesp......
  • MYSQL将一行数据的多列值放到另一列的多个行中
    在MySQL中,如果你想要将一行数据的多列值放到另一列的多个行中,你可以使用一个辅助表(例如,使用nums表)来生成序列,然后与你的原始表进行联接。比如下面一行一行数据,包含col1~col5总共5列,现在需要将这5类转换到一列中。转换前的数据:转换后的结果: 以下是一个示例:首先,创建一个辅......
  • SQL Server 数据库如何优化?
    合集-威哥爱编程(44) 1.35个Redis企业级性能优化点与解决方案06-252.对比传统数据库,TiDB强在哪?谈谈TiDB的适应场景和产品能力06-253.深度长文解析SpringWebFlux响应式框架15个核心组件源码07-044.Nginx性能调优5招35式不可不知的策略实战07-085.JavaExecutors类的9种......
  • T-SQL——自定义函数解析JSON字符串
    T-SQL——自定义函数解析JSON字符串适应于是2005及以上版本1.函数创建脚本CREATEFUNCTION[dbo].[parseJSON](@JSONNVARCHAR(MAX))/**Summary:>ThecodefortheJSONParser/ShredderwillruninSQLServer2005,andeveninSQLServer2000(withsomemo......
  • MySQL 5.7.19 解压版安装配置详细教程
    MySQL5.7.19解压版安装配置详细教程1.软件下载首先,从MySQL官方网站下载MySQL5.7.19的解压版安装文件:下载地址:https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip2.特别说明如果你之前安装过MySQL,并且出现了错误或者想要重新安装,可以使用以......
  • DVWA SQL注入union
    数字型注入1and1=11and1=2返回数据不一样则有注入点且为数字型注入//判断列数?id=and1orderby6//返回正确?id=and1orderby7//返回错误得到列数为6查数据库:1and1=2unionselect1,database()字符型注入'and1=1and'1'='1'and1=2and'1'='1?id......
  • 基于Java+SpringBoot+Mysql在线课程学习教育系统功能设计与实现五
    一、前言介绍:免费获取:猿来入此1.1项目摘要随着信息技术的飞速发展和互联网的普及,教育领域正经历着深刻的变革。传统的面对面教学模式逐渐受到挑战,而在线课程学习教育系统作为一种新兴的教育形式,正逐渐受到广泛关注和应用。在线课程学习教育系统的出现,不仅为学生提供了更加灵......