基于SQLServer2008的SQL调优(转)

1. 前言

SQL是程序设计人员与数据库进行沟通的标准语言,在数据库应用程序中,使用最多的访问数据库的方法就是SQL语言。SQL性能的调整涉及到SQLServer 2008的方方面面,优化器的选择、内存参数的设定、SQL语句的写法等。本文主要从SQL语句的优化方面进行阐述,给出了一些可行的调整数据库应用性能的策略与方法,并以SQLServer 2008为平台对列举规则给予了验证。

2. 实验环境

  • 硬件环境:Inter(R) Core(TM)2 Duo CPU P7450 @2.12GHz 、2G内存。
  • 操作系统:windows7操作系统,
  • SQL Server 2008版本:Microsoft SQLServer 2008
  • 所用表结构:
    • Consume(ConsumeID,Cardno,ShopId,GoodsId,Amount,ConsumeDate)
    • CreditCard(Cardno,OwnerName,IDCard,MaxConsume,Address,PostCode,Phone,ConsumeAmount)
    • Goods(GoodId,GoodsName,TypeId,ShopId,Price)
    • Shop(ShopId,ShopName)
  • 记录数:Consume:686302    CreditCard:9    Goods:32    Shop:4

本实验是在SQL Server Management Studio平台上执行的。且运行时均利用 DBCC FREEPROCCACHE  DBCCDROPCLEANBUFFERS  DBCC FREESYSTEMCACHE (‘ALL‘ )这三条语句清理了缓冲区,从而得出相对公平的执行时间

另外,每段实验代码均放入如下代码中间执行,这样可以得到SQL语句执行所用的时间,获取执行时间的代码如下:

[sql] view plaincopy

  1. declare @begin_date datetime
  2. declare @end_date datetime
  3. select @begin_date = getdate()
  4. <实验SQL语句写在此处>
  5. select @end_date = getdate()
  6. select datediff(ms,@begin_date,@end_date) as ‘用时/毫秒‘

3. SQL调优

3.1 优化SELECT语句

如果查询数据时涉及多个表,则通常需要使用连接查询。SQL Server 2008支持内连接、外连接和交叉连接等连接查询方式。

3.1.1 连接查询的优化

子查询替换连接表

低效语句:

[sql] view plaincopy

  1. select c.cardno,cc.IDCard,c.amount,c.consumedate
  2. from CreditCard cc left join Consume c
  3. on cc.Cardno = c.Cardno
  4. where c.Cardno = ‘9555xxxxxxx1‘

高效语句:

[sql] view plaincopy

  1. select @begin_date = getdate()
  2. select c.cardno,cc.IDCard,c.amount,c.consumedate
  3. from (select * from CreditCard where Cardno = ‘9555xxxxxxx1‘) ccleft join Consume c
  4. on cc.Cardno = c.Cardno

执行结果分别如下:

3.1.2控制查询的行和列

优化SELECT语句,首先需要考虑的是减少返回结果集中的数据量。在SELECT语句中,应该尽量可能不返回多余的数据,这需要从行和列两方面进行优化。

减少结果集中列的数量:

低效语句:

[sql] view plaincopy

  1. select  *
  2. from CreditCard cc left joinConsume c
  3. on cc.Cardno = c.Cardno
  4. where c.Cardno = ‘9555xxxxxxx1‘

高效语句:

[sql] view plaincopy

  1. select @begin_date = getdate()
  2. selectc.cardno,cc.IDCard,c.amount,c.consumedate
  3. from CreditCard cc left join Consume c
  4. on cc.Cardno = c.Cardno
  5. where c.Cardno = ‘9555xxxxxxx1‘

执行结果分别如下:

3.1.3 慎用DISTINCT关键字

DISTINCT关键字一般用来于字段很少的表,如果在SELECT语句中查询的字段很多,则使用DISTINCI关键字反而会大大降低查询的效率。

低效语句(使用DISTINCT):

[sql] view plaincopy

  1. select distinctc.cardno,cc.OwnerName,cc.IDCard,s.shopname,
  2. g.goodsname,c.amount,c.consumedate
  3. from Consume c inner join CreditCard cc
  4. on cc.Cardno = c.Cardno
  5. inner join Shop s on c.ShopId=s.ShopId
  6. inner join Goods g onc.GoodsId=g.GoodsId

高效语句(不使用DISTINCT):

[sql] view plaincopy

  1. selectc.cardno,cc.OwnerName,cc.IDCard,s.shopname,
  2. g.goodsname,c.amount,c.consumedate
  3. from Consume c inner join CreditCard cc
  4. on cc.Cardno = c.Cardno
  5. inner join Shop s on c.ShopId=s.ShopId
  6. inner join Goods g onc.GoodsId=g.GoodsId

执行结果分别如下:

3.1.4 判断表中是否存在记录

有些人喜欢使用COUNT(*)来判断表中是否存在记录,例如

[sql] view plaincopy

  1. select count(*) from consume

这种方法要统计表中所有记录的总数量,因此执行效率比较低。可以在select语句中使用TOP1返回表中的第一条记录来判断表是否存在记录:

低效语句:

[sql] view plaincopy

  1. select COUNT(*) from Consume

高效语句:

[sql] view plaincopy

  1. select top 1 ConsumeID from Consume

执行结果分别如下:

3.2 对大批量插入、修改和删除数据操作的优化

3.2.1 使用SQL脚本模拟实时批量插入数据

[sql] view plaincopy

  1. -- 使用Credit数据库
  2. USE Credit
  3. GO
  4. -- 创建临时表#test
  5. CREATE TABLE #test
  6. (
  7. id int,
  8. name varchar(100),
  9. createdate datetime,
  10. )
  11. GO
  12. DECLARE @i as INT
  13. declare @strsql as varchar(8000)
  14. SET @i = 0
  15. -- 循环插入10万条记录
  16. WHILE @i < 100000
  17. BEGIN
  18. SET @strsql = ‘INSERT INTO #test VALUES(‘ + convert(varchar(100), @i) + ‘, ‘‘test‘‘, ‘‘‘ + convert(varchar(50), getdate()) + ‘‘‘)‘ --VALUES(@i, ‘test‘, getdate())
  19. exec(@strsql)
  20. SET @i = @i + 1
  21. END

从下面两张图我们可以看出,计算机的CUP使用率一直居高不下看,这样会严重影响系统性能,导致用户无法正常使用数据库应用程序。

下面我们对批量插入数据进行优化,可以使用WAITFOR DELAY语句进行休息,例如,让数据库引擎休息100ms的代码如下:

[sql] view plaincopy

  1. WQITFOR DELAY ’00:00:00:100’

优化后的SQL脚本如下:

[sql] view plaincopy

  1. -- 使用Credit数据库
  2. USE Credit
  3. GO
  4. -- 创建临时表#test
  5. CREATE TABLE #test
  6. (
  7. id int,
  8. name varchar(100),
  9. createdate datetime,
  10. )
  11. GO
  12. DECLARE @i as INT
  13. declare @strsql as varchar(8000)
  14. SET @i = 0
  15. -- 循环插入10万条记录
  16. WHILE @i < 100000
  17. BEGIN
  18. SET @strsql = ‘INSERT INTO #test VALUES(‘ + convert(varchar(100), @i) + ‘, ‘‘test‘‘, ‘‘‘ + convert(varchar(50), getdate()) + ‘‘‘)‘ --VALUES(@i, ‘test‘, getdate())
  19. exec(@strsql)
  20. WAITFOR DELAY ‘00:00:00:20‘
  21. SET @i = @i + 1
  22. END

执行此脚本,我们再来查看CUP的使用情况:

CPU的占用率已经降到5%左右,虽然执行的时间增加了,但是这完全满足系统正常运行的需要。

3.2.2 优化修改和删除语句

如果一条UPDATE语句或者DELETE语句设计的记录过多,则执行语句的时间会很长,在执行语句的过程中,数据库服务器的CPU利用率会很高,从而影响其他用户对数据库的访问效率。当对大量数据进行更新和删除操作时,可以根据用户的具体情况来决定操作的方式。

a)如果在非工作时间执行大量更新或者删除操作,则应该尽可能地在一条语句中更新更多的记录,这是最快的操作方式。

b)如果在工作时间执行大量更行或删除操作,则应该根据实际情况将UPDATE语句或者DELETE语句拆分成多条语句,每执行一条语句休息一段时间。

下面做一个对比实验,执行下面的UPDATE语句,将表Consume中所有记录的Amount数量增加10%。

[sql] view plaincopy

  1. update Consume set Amount = Amount * 1.1 whereConsumeID>0

执行结果如下:

CPU的使用率一直维持在60%左右:

如果希望在执行更新操作时尽可能降低数据库服务器的CPU使用率,不影响其他用户对数据库的访问,可以使用下面的SQL语句:

[sql] view plaincopy

  1. update Consume set Amount = Amount*1.1where Amount<200
  2. waitfor delay ‘00:00:00:100‘
  3. update Consume set Amount = Amount*1.1where Amount>=200 and Amount<500
  4. waitfor delay ‘00:00:00:100‘
  5. update Consume set Amount = Amount*1.1where Amount>=1000 and Amount<2000
  6. update Consume set Amount = Amount*1.1where Amount>2000
  7. waitfor delay ‘00:00:00:100‘

从下图的数据可知,CPU的占用率与前面的比较降低了不少。

4. 总结

在SQL Server 2008中性能的优化还有许多方面,如存储引擎优化、处理器管理优化、视图的优化等等。以上实验只是针对SQL Server 2008中的SQL语句进行调优。本文中的实验所测得的SQL执行时间会有微小误差,这是不能避免的。更进一步的数据库优化操作有待于进一步的学习和总结。

时间: 2024-10-12 09:00:34

基于SQLServer2008的SQL调优(转)的相关文章

SQL调优日志--内存问题

SQL调优日志--内存问题排查入门篇 概述 很多系统的性能问题,是由内存导致的.内存不够会导致页面频繁换入换出,IO队列高,进而影响数据库整体性能. 排查 内存对数据库性能非常重要.那么我当出现问题的时候,我们怎么排查性能问题呢? 存在问题 主要查看2个部分.页生命周期 Page Life Expectancy,和  lazy writer /sec. 页生命周期 的参考值在很久很久以前,很多同学可能看到过,建议值是300s.但是这是基于32位操作系统,最大只能使用4GB内存给出的. Jonat

SQL调优

# 问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一.系统优化中一个很重要的方面就是SQL语句的优 化.对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的 SQL语句,提高系统的可用性. 在多数情况下,Oracle

MySQL索引和SQL调优

MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree索引,因为这是平常使用MySQL时主要打交道的索引. MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. MySQL索引原理 索引目的 索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,

Oracle SQL 调优健康检查脚本

Oracle SQL 调优健康检查脚本 我们关注数据库系统的性能,进行数据库调优的主要工作就是进行SQL的优化.良好的数据架构设计.配合应用系统中间件和写一手漂亮的SQL,是未来系统上线后不出现致命性能问题的有力保证. 在CBO时代,一个SQL的执行计划是多样的.影响执行计划的因素也从过去RBO时代的SQL书写规则变为综合性因素.这为我们生成更加优秀执行计划提供了基础,同时也给我们进行调优带来的很多麻烦. 目前我们通常的做法,是通过AWR报告或者调试手段,发现某某SQL有问题,之后从Librar

11g新特性-自动sql调优(Automatic SQL Tuning)

11g新特性-自动sql调优(Automatic SQL Tuning) 在Oracle 10g中,引进了自动sql调优特性.此外,ADDM也会监控捕获高负载的sql语句. 在Oracle 11g中,通过运行sql tuning advisor加强了自动sql调优功能.默认情况下是每天夜间通过自动任务的方式运行"自动sql调优". 自动sql调优的过程: 1.识别需要调优的sql语句  根据AWR中的CPU和I/O负载来识别 2.调优,生成新的sql profile 在维护窗口(mai

SQL调优常用方法

在使用DBMS时经常对系统的性能有非常高的要求:不能占用过多的系统内存和 CPU资源.要尽可能快的完成的数据库操作.要有尽可能高的系统吞吐量.如果系统开发出来不能满足要求的所有性能指标,则必须对系统进行调整,这个工作被称为调优.绝定DBMS的性能的因素有两个因素:硬件和软件.使用频率高的CPU.使用多处理器.加大内存容量.增加Cache.提高网络速度等这些都是非常有效的硬件调优方式,不过对硬件进行调优对系统性能的提高是有限的,如果有非常好的硬件条件但是如果编写的SQL质量非常差的话系统的性能并不

数据库学习——SQL调优

一.SQL调优与查询优化器 数据库性能调优一般从发现.分析和解决SQL语句执行中的问题着手,这个过程统称为SQL调优(SQL tuning). 1.了解查询优化器 例如,有些查询优化器对于连接操作,一般按连接对象在FROM子句中出现的先后次序进行连接.SQL程序设计者可以利用此特点将选择性高的小表放在前面,大表放在后面,以尽快淘汰无用的中间结果,从而节省查询处理开销.又如,有些查询优化器中,凡是查询条件用OR连接的,就一概不用索引,因而只能用全表扫描,可以考虑使用UNION ALL代替OR. 2

oracle sql调优集

************************************************************ 1.新建调优集对象 ************************************************************ ---授权 grant ADMINISTER ANY SQL TUNING SET to scott; ---删除存在的STS BEGIN DBMS_SQLTUNE.DROP_SQLSET( sqlset_name => 'OCPYAN

初次使用SQL调优建议工具--SQL Tuning Advisor

在10g中,Oracle推出了自己的SQL优化辅助工具: SQL优化器(SQL Tuning Advisor :STA),它是新的DBMS_SQLTUNE包. 使用STA一定要保证优化器是CBO模式下.可是我觉得使用这样的工具,仅适合全然不懂SQL的调优的人群,不要觉得工具能解决好问题. SQL说究竟是表达的是一个业务,工具怎么可能理解业务.SQL调优还是要用autotrace,10046,10053,display_cursor这些优秀的工具做诊断.然后依据业务和所具备的oracle基础的知识