SQL语句的优化分析

sql语句性能达不到你的要求,执行效率让你忍无可忍,一般会时下面几种情况。

  网速不给力,不稳定。

  服务器内存不够,或者SQL 被分配的内存不够。

  sql语句设计不合理

  没有相应的索引,索引不合理

  没有有效的索引视图

  表数据过大没有有效的分区设计

  数据库设计太2,存在大量的数据冗余

  索引列上缺少相应的统计信息,或者统计信息过期

  ....

  那么我们如何给找出来导致性能慢的的原因呢?

  首先你要知道是否跟sql语句有关,确保不是机器开不开机,服务器硬件配置太差,没网你说p啊

  接着你使用我上一篇文章中提到的2柯南sql性能检测工具--sql server profiler,分析出sql慢的相关语句,就是执行时间过长,占用系统资源,cpu过多的

  然后是这篇文章要说的,sql优化方法跟技巧,避免一些不合理的sql语句,取暂优sql

  再然后判断是否使用啦,合理的统计信息。sql server中可以自动统计表中的数据分布信息,定时根据数据情况,更新统计信息,是很有必要的

  确认表中使用啦合理的索引,这个索引我前面博客中也有提过,不过那篇博客之后,还要进一步对索引写篇文章

  数据太多的表,要分区,缩小查找范围

  分析比较执行时间计划读取情况

  select * from dbo.Product

  执行上面语句一般情况下只给你返回结果和执行行数,那么你怎么分析呢,怎么知道你优化之后跟没有优化的区别呢。

  下面给你说几种方法。

  1.查看执行时间和cpu占用时间

  set statistics time on

  select * from dbo.Product

  set statistics time off

  打开你查询之后的消息里面就能看到啦。

  2.查看查询对I/0的操作情况

  set statistics io on

  select * from dbo.Product

  set statistics io off

  执行之后


 扫描计数:索引或表扫描次数

  逻辑读取:数据缓存中读取的页数

  物理读取:从磁盘中读取的页数

  预读:查询过程中,从磁盘放入缓存的页数

  lob逻辑读取:从数据缓存中读取,image,text,ntext或大型数据的页数

  lob物理读取:从磁盘中读取,image,text,ntext或大型数据的页数

  lob预读:查询过程中,从磁盘放入缓存的image,text,ntext或大型数据的页数

  如果物理读取次数和预读次说比较多,可以使用索引进行优化。

  如果你不想使用sql语句命令来查看这些内容,方法也是有的,哥教你更简单的。

  查询--->>查询选项--->>高级

  被红圈套上的2个选上,去掉sql语句中的set statistics io/time on/off 试试效果。哦也,你成功啦。。

  3.查看执行计划

  首先我这个例子的语句太过简单,你整个复杂的,包涵啊。

  分析:鼠标放在图标上会显示此步骤执行的详细内容,每个表下面都显示一个开销百分比,分析站百分比多的的一块,可以根据重新设计数据结构,或这重写sql语句,来对此进行优化。如果存在扫描表,或者扫描聚集索引,这表示在当前查询中你的索引是不合适的,是没有起到作用的,那么你就要修改完善优化你的索引,具体怎么做,你可以根据我上一篇文章中的sql优化利器--数据库引擎优化顾问对索引进行分析优化。

  select查询艺术

  1.保证不查询多余的列与行。

  尽量避免select * 的存在,使用具体的列代替*,避免多余的列

  使用where限定具体要查询的数据,避免多余的行

  使用top,distinct关键字减少多余重复的行

  2.慎用distinct关键字

  distinct在查询一个字段或者很少字段的情况下使用,会避免重复数据的出现,给查询带来优化效果。

  但是查询字段很多的情况下使用,则会大大降低查询效率。

  由这个图,分析下:

  很明显带distinct的语句cpu时间和占用时间都高于不带distinct的语句。原因是当查询很多字段时,如果使用distinct,数据库引擎就会对数据进行比较,过滤掉重复数据,然而这个比较,过滤的过程则会毫不客气的占用系统资源,cpu时间。

  3.慎用union关键字

  此关键字主要功能是把各个查询语句的结果集合并到一个结果集中返回给你。用法

  <select 语句1>

  union

  <select 语句2>

  union

  <select 语句3>

  ...

  满足union的语句必须满足:1.列数相同。 2.对应列数的数据类型要保持兼容。

  执行过程:

  依次执行select语句-->>合并结果集--->>对结果集进行排序,过滤重复记录。


select * from

(( orde o  left join orderproduct op on o.orderNum=op.orderNum )

inner join product p on op.proNum=p.productnum)  where p.id<10000

union

select * from

(( orde o  left join orderproduct op on o.orderNum=op.orderNum )

inner join product p on op.proNum=p.productnum)  where p.id<20000 and p.id>=10000

union

select * from

(( orde o  left join orderproduct op on o.orderNum=op.orderNum )

inner join product p on op.proNum=p.productnum)  where p.id>20000   ---这里可以写p.id>100 结果一样,因为他筛选过啦

----------------------------------对比上下两个语句-----------------------------------------

select * from

(( orde o  left join orderproduct op on o.orderNum=op.orderNum )

inner join product p on op.proNum=p.productnum)

  由此可见效率确实低,所以不是在必要情况下避免使用。其实有他执行的第三部:对结果集进行排序,过滤重复记录。就能看出不是什么好鸟。然而不对结果集排序过滤,显然效率是比union高的,那么不排序过滤的关键字有吗?答,有,他是union all,使用union all能对union进行一定的优化。。

 4.判断表中是否存在数据

  select count(*) from product

  select top(1) id from product

  很显然下面完胜

  5.连接查询的优化

  首先你要弄明白你想要的数据是什么样子的,然后再做出决定使用哪一种连接,这很重要。

  各种连接的取值大小为:

  内连接结果集大小取决于左右表满足条件的数量

  左连接取决与左表大小,右相反。

  完全连接和交叉连接取决与左右两个表的数据总数量

  select * from

  ( (select * from orde where OrderId>10000) o  left join orderproduct op on o.orderNum=op.orderNum )

  select * from

  ( orde o left join orderproduct op on o.orderNum=op.orderNum )

  where o.OrderId>10000

  由此可见减少连接表的数据数量可以提高效率。

  insert插入优化

  --创建临时表


create table #tb1

(

id int,

name nvarchar(30),

createTime datetime

)

declare @i int

declare @sql varchar(1000)

set @i=0

while (@i<100000)  --循环插入10w条数据

begin

set @i=@i+1

set @sql=' insert into #tb1 values('+convert(varchar(10),@i)+',''erzi'+convert(nvarchar(30),@i)+''','''+convert(nvarchar(30),getdate())+''')'

exec(@sql)

end

  我这里运行时间是51秒

  --创建临时表


create table #tb2

(

id int,

name nvarchar(30),

createTime datetime

)

declare @i int

declare @sql varchar(8000)

declare @j int

set @i=0

while (@i<10000)  --循环插入10w条数据

begin

set @j=0

set @sql=' insert into #tb2 select '+convert(varchar(10),@i*100+@j)+',''erzi'+convert(nvarchar(30),@i*100+@j)+''','''+convert(varchar(50),getdate())+''''

set @i=@i+1

while(@j<10)

begin

set @sql=@sql+' union all select '+convert(varchar(10),@i*100+@j)+',''erzi'+convert(nvarchar(30),@i*100+@j)+''','''+convert(varchar(50),getdate())+''''

set @j=@j+1

end

exec(@sql)

end

drop table #tb2

select count(1) from #tb2

  我这里运行时间大概是20秒

  分析说明:insert into select批量插入,明显提升效率。所以以后尽量避免一个个循环插入。

  优化修改删除语句

  如果你同时修改或删除过多数据,会造成cpu利用率过高从而影响别人对数据库的访问。

  如果你删除或修改过多数据,采用单一循环操作,那么会是效率很低,也就是操作时间过程会很漫长。

  这样你该怎么做呢?

  折中的办法就是,分批操作数据。

  delete product where id<1000

  delete product where id>=1000 and id<2000

  delete product where id>=2000 and id<3000

  .....

  当然这样的优化方式不一定是最优的选择,其实这三种方式都是可以的,这要根据你系统的访问热度来定夺,关键你要明白什么样的语句是什么样的效果。

  总结:优化,最重要的是在于你平时设计语句,数据库的习惯,方式。如果你平时不在意,汇总到一块再做优化,你就需要耐心的分析,然而分析的过程就看你的悟性,需求,知识水平啦。

最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2025-01-20 20:36:41

SQL语句的优化分析的相关文章

改进数据库SQL语句进行优化的理由

数据|数据库|优化|语句 应用程序的优化通常可分为两个方面:源代码的优化和SQL语句的优化.源代码的优化在时间成本和风险上代价很高:另一方面,源代码的优化对数据库系统性能的提升收效有限. 优化的理由 1)SQL语句是对数据库(数据)进行操作的惟一途径: 2)SQL语句消耗了70%~90%的数据库资源: 3)SQL语句独立于程序设计逻辑,相对于对程序源代码的优化,对SQL语句的优化在时间成本和风险上的代价都很低: 4)SQL语句可以有不同的写法: 5)SQL语句易学,难精通. 优化技术的发展 第一

[20150715]一条sql语句的优化.txt

[20150715]一条sql语句的优化.txt --生产系统发现一条语句. update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') --第1眼看到的感觉真的很想骂人,什么能没有where条件呢? --我把这个表拷贝过来.这个表占用1G多1点,在测试环境执行看看: -- copy from system/xxxx@ip:1521/tyt create presc_check using select * f

sql server-求助:sqlserver一条sql语句的优化 是否需要索引 建立什么样的索引合适

问题描述 求助:sqlserver一条sql语句的优化 是否需要索引 建立什么样的索引合适 1C select COUNT(*) total from (select distinct(device_token) from MDM_POLICY_UPDATE where len(device_token)=64 and SW='crmi_poly') a 解决方案 我觉得直接可以用count(device_token) 然后直接groupby device个人感觉最拖后腿的应该是len()这个函

sql-求下面这段SQL语句的优化

问题描述 求下面这段SQL语句的优化 update #temp set res = ( select top 1 [Desc] from Response nolock where req_no = ( select top 1 req_no from Request nolock where id = #temp.id order by update_date desc ) order by update_date desc ), [pro_status] = ( select top 1 [

Oracle数据库中SQL语句的优化技巧_oracle

在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化. 例如: SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 2. /*+FIRST_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.

SQL语句性能优化(续)_MsSql

上篇介绍了一下自己在项目中遇到的一种使用sql语句的优化方式(性能优化--SQL语句),但是说的不够完整.在对比的过程中,没有将max函数考虑在内,经人提醒之后赶紧做了一个测试,测试过程中又学到了不少的东西. 上次用的是select count(*) 和select * 的执行效率问题,因为我的需求是获取数据的一个总数来自动给出新的id,然后网友给出可以使用max的方式给出新id.其实这也是一种不错的思路(当时我们也用过该函数,只不过因为系统数据本身问题,不适合用该函数),然后我就对max函数的

请教大神一条sql语句的优化

问题描述 请教大神一条sql语句的优化 表名pm,以temp分组,count两个信息,一个是全部个数,另一个是status为1 id temp status 1 1 0 2 1 1 3 2 0 4 2 1 5 2 1 select total.temp ,used.c1,total.c2 from (select temp,count(1) c1 from pm group by temp ) total left join (select temp,count(1) c2 from pm wh

Oracle之SQL语句性能优化(34条优化方法)_oracle

好多同学对sql的优化好像是知道的甚少,最近总结了以下34条仅供参考. (1)选择最有效率的表名顺序(只在基于规则的优化器中有效): ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. (2) WH

SQL语句性能优化(续)

上篇介绍了一下自己在项目中遇到的一种使用sql语句的优化方式(性能优化--SQL语句),但是说的不够完整.在对比的过程中,没有将max函数考虑在内,经人提醒之后赶紧做了一个测试,测试过程中又学到了不少的东西. 上次用的是select count(*) 和select * 的执行效率问题,因为我的需求是获取数据的一个总数来自动给出新的id,然后网友给出可以使用max的方式给出新id.其实这也是一种不错的思路(当时我们也用过该函数,只不过因为系统数据本身问题,不适合用该函数),然后我就对max函数的