面试中的SQL优化问题

1、sql优化

1.1 SQL语言

结构化查询语言(Structured Query Language)的简称,

是一种数据库查询和程序设计语言

用于存取数据以及查询更新管理关系数据库系统,也是数据库脚本文件的扩展名

1.2 SQL优化

定位有问题的语句,检查执行计划,检查执行过程中优化器的统计信息,分析相关表的记录数、索引情况改写SQL语句、使用HINT、调整索引、表分析有些SQL语句不具备优化的可能,需要优化处理方式达到最佳执行计划

为了获得稳定的执行性能,SQL语句越简单越好

但是最佳的执行计划不一定是最佳的执行情况,一切以实际执行的情况为准。

2、sql优化的几种途径

第一部分:数据表格创建时:

1、选择合适的存储引擎(MySQL)
1.0 什么是存储引擎

存储引擎就是存储数据建立索引更新查询数据等等技术的实现方式

存储引擎是基于表,而不是基于库的。

所以存储引擎也可被称为表类型

存储引擎的概念是MySQL的特点,Oracle中没有专门的存储引擎的概念,但Oracle有OLTP和OLAP模式的区分。

存储引擎决定MySQL数据库中的表用什么样的方式来存储。

我们可以根据数据的特点来选择不同的存储引擎。

引擎包括三种,innodb、myisam、memory。

1.1 innoDB(默认引擎)

优势在于提供了良好的事务处理、崩溃修复能力和并发控制,支持回滚。

缺点是读写效率较差,占用的数据空间相对较大(连表查询)。

MySQL支持外键的存储引擎只有InnoDB

在创建外键的时候,要求父表必须有对应的索引,子表在创建外键的时候,也会自动的创建对应的索引。

1.2 myisam

提供了高速检索和存储的能力,支持全文索引

MyISAM不支持事务、也不支持外键

其优势是访问速度快

对事物的完整性没有要求或者以SELECT、INSERT为主的应用基本上都可以使用这个

① myisam的表存储成3个文件。

② 文件的名字与表名相同。

​ 拓展名为:

frm(frm文件存储表的结构)

MYD(MYD文件存储数据,MYData的缩写)

MYI(MYI文件存储索引,MYIndex的缩写)

③ myisam存储引擎的表支持以下3种不同的存储格式:

静态型:

MyISAM的默认存储格式

它的字段是固定长度的,使表具有极高的访问速度

缺点就是占用空间比较大

动态型:

动态型包含变长字段,记录的长度不是固定的,

优点是它存数据时,采用的是数据的实际长度,能节省不少空间,

缺点是由于采用了数据的实际长度,每当数据更新,长度发生变更时,就变换了位置,使得原来得变得位置空闲,并且关联的数据并不是存放在相邻的块中,而且产生大量的碎片,需要定期进行碎片整理

压缩型:

压缩型要用到myisampack工具,

空间占用相当小,只有原大小的一半,

而且读取数据时,还会对数据进行加压缩,

这个类型的表是只读表,不能进行修改.

1.3 memory

每个基于MEMORY存储引擎的表实际对应一个磁盘文件

该文件的文件名与表名相同,类型为frm类型(frm文件存储表的结构)。

而它的数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率

值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。

如果不需要了,可以释放内存,甚至删除不需要的表

MEMORY默认使用哈希索引

MEMORY用到的很少,因为它是把数据存到内存中,如果内存出现异常就会影响数据

如果重启或者关机,所有数据都会消失

因此,基于MEMORY的表的生命周期很短,一般是一次性

2、Oracle的OLTP和OLAP模式的区分
2.1 OLTP联机事务处理

(on-line transaction processing):

属于高可用的在线系统,注重事务,高响应,高并发(多人同时使用)

操作语句,尽量以最简单的增删查改为主,避免复杂SQL

这个模式是Oracle数据库也是传统关系型数据库的主要应用模式

OLTP模式的应用场景,在日常中很常见:比如在线订票,银行交易,电子商务等等。

2.2 OLAP联机分析处理

(On-Line Analytical Processing):

用于做复杂的SQL关联和数据分析,向高层展示汇总数据(也就是各种报表),最终用于支撑决策。

也类似与平常说的数据仓库

Oracle的OLAP模式在以前应用更多一些,但是通过最近几年大数据的热潮,Oracle的这个模式逐渐会被淘汰掉,更多会使用大数据系列工具(Hadoop系列)。

Hadoop系列:

一是对于PB级别的数据,Oracle的OLAP模式几乎毫无应对之法,单机处理性能始终有限,而Hadoop系列采用分布式存储,分布式处理,能横向扩展对于TB和PB级别的数据量都能有良好的处理性能。

二是Hadoop系列开源,免费,强一点的公司还可以自己做定制化,而Oracle不开源,维护费用昂贵。

当然,Oracle的OLAP模式现在还没有被淘汰,毕竟Hadoop的稳定性还在日趋完善,产品的替换也是需要很多人力,财力的投入。

3、设置表格字段时

使用varchar代替char

因为变长字段记录的长度不是固定的,存储时采用的是数据的实际长度,节省空间。

采用数字型字段

若只含数值信息的字段尽量不要设计为字符型,因为这会降低查询和连接的性能,并会增加存储开销。

也是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,

而对于数字型而言只需要比较一次就够了

4、创建表格时

添加索引,可以增加查询的速度

太多的索引会降低insert和update的效率

因为插入和更新时有可能会重建索引

一个表的索引最好不要超出6个

具体要根据需要确定是否有必要添加索引

第二部分sql语句部分:

《 数据库技术内幕 》

减少数据访问: 设置合理字段类型,启用压缩,通过索引访问等减少磁盘IO(读写操作)

返回更少的数据: 只返回需要的字段和数据分页处理 减少磁盘io及网络io

减少交互次数: 批量DML操作(数据操纵语言),函数存储等减少数据连接次数

减少服务器CPU开销: 尽量减少数据库排序操作,和全表查询 减少cpu 内存占用

利用更多资源: 使用表分区(记录硬盘文件的地址),可以增加并行操作,更大限度利用cpu资源

1、尽量避免全表查询

用具体的字段列表代替“*”,不要返回用不到的任何字段,否则会占用内存

禁止使用select *,

只获取需要的字段–查询很多无用字段,

增加CPU/IO/NET消耗;

不能有效的利用覆盖索引;

增删字段易出bug

不要出现 select * from table 的情况,优先考虑 where 和 order by

2、避免使用太过复杂的sql语句查询

尤其是出现嵌套的时候,

最好不要出现三层以上的嵌套,

否则会影响查询效率

3、考虑使用临时表暂存

简化SQL语句的重要方法就是采用临时表暂存中间结果,

将临时结果暂存在临时表,可以避免程序中多次扫描主表

也要避免频繁创建和删除临时表,以减少系统表资源的消耗

在新建临时表时,如果一次性插入数据量很大,

那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;

如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,

先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

4.应尽量避免在 where 子句中对字段进行 null 值判断

否则导致引擎放弃使用索引而进行全表扫描,降低效率

如:
select id from t where num is null

可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

​ select id from t where num=0

5.应尽量避免在 where 子句中使用!=或<>操作符

否则引擎放弃使用索引而进行全表扫描,降低效率

6.应尽量避免在 where 子句中使用 or 来连接条件

否则导致引擎放弃使用索引而进行全表扫描,降低效率

如:
select id from t where num=10 or num=20

可以这样查询:

​ select id from t where num=10
​ union all
​ select id from t where num=20

7.in 和 not in 也要慎用

**否则会导致全表扫描,**降低效率

如:
select id from t where num in(1,2,3)

对于连续的数值,能用 between 就不要用 in 了:

​ select id from t where num between 1 and 3

8.模糊查询也将导致全表扫描

注意使用like的时候尽量不要使用“%a%”,这样的不走索引,可以使用“a%”,走索引

select id from t where name like ‘%abc%’

9.应尽量避免在 where 子句中对字段进行表达式操作

否则会导致引擎放弃使用索引而进行全表扫描,降低效率

如:
select id from t where num/2=100

应改为:

​ select id from t where num=100*2

10.应尽量避免在where子句中对字段进行函数操作

否则会导致引擎放弃使用索引而进行全表扫描,降低效率

如:
select id from t where substring(name,1,3)=‘abc’–name以abc开头的id

应改为:

​ select id from t where name like ‘abc%’

11.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,

否则系统将可能无法正确使用索引

12.不要写一些没有意义的查询

会消耗系统资源

如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0

​ 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

​ create table #t(…)

13.最好用 exists 代替 in

速度更快

​ select num from a where num in(select num from b)

​ 用下面的语句替换:

​ select num from a where exists(select 1 from b where num=a.num)

exists 方式查询 比 in 方式查询效率高,但in 可读性较好。

建议尽可能使用exists方式,避免使用子查询(将结果保存在临时表中),除非in 的参数为数值列表。

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值