当确定了应用性能问题可以归结到某一个,或者几个耗时资源的语句后,对这些语句进行调优,就是数据库管理员或者数据库应用程序开发者当仁不让的职责了。语句调优是和数据库打交道的必备基本功之一。

当你面对一个“有问题”的语句时,应该怎么分析它的问题所在,最后达到优化语句的目的呢?首先要想一想,“有问题”的语句“问题”究竟在那里?也就是说,你要优化的目标是什么。常见的需求有:

1)         语句需要访问大量的数据页面,造成内在压力、磁盘繁忙等。

对于这类问题,所关心的是为什么语句要执行要访问这么多数据页面?是语句的结果集本身就比较大;还是SQL SERVER没有办法有效地seek,而是像大炮打苍蝇一样从大量的原始数据里找出需要返回的结果;还是因为数据页面里有很多碎片,导致SQL SERVER读了很多页面,但是每个页面里的数据量不多。这些都是要考虑的因素。

2)         在内存没有压力的前提下(语句所访问的页面都事先缓存在内存里),语句运行的时间还是很长。

语句的运行时间一般会主要花在这3步上:语句编译、语句执行和结果集返回。结果集返回的速度和SQL SERVER自身没有太大关系,所以一般不会在语句调优的时候来考虑。语句调优时要搞清楚编译和执行各花了多少时间,哪 一段时间有优化的空间,以及怎么来优化。

3)         单个语句执行时间可以接受,但是苦CPU使用量比较大,多个语句并发执行会造成SQL SERVER CPU高。

有些语句单句执行可能一两秒钟就能执行完毕,对用户来讲还在可接受的范围。但是它的CPU间可能也是在一两秒,甚至更长。如果同时有十几个用户在跑同样的语句,SQL SERVER 就会满负荷了。语句的CPU时间也分编译阶段和执行阶段。优化者要先搞清楚这两个阶段各用了多少CPU资源,然后再看看有没有优化降低CPU使用量的可能。

4)         语句单独执行看不出有大问题,但是并发执行就容易遇到阻塞和死锁。

这个也是语句调优的一个重要任务。很多语句执行速度很快,使用资源量SQL SERVER也能够承受,但是就是容易引起阻塞和死锁。这种现象往往是由于应用在某个表或者索引上的并发度特别高,而问题语句申请的锁数量比较大造成的。当然有时候可以使用Query Hint 来强制 SQL SERVER使用粒度比较小的锁。但是这往往不是最好的解决办法,也可能解决不了问题。最理想的方法,是通过调整语句运行方式,引导它申请尽可能少的、粒度尽可能小的锁。这里也要做语句调优。

在做这些调优的时候,首先要对目标语句做估算,看看它优化的空间有多大。有些语句本身比较简单,可以通过调整索引的方法迅速提高性能,这样的调优是很值得做的。有些语句非常复杂,或者返回的结果集很大,通过调整SQL SERVER这里的设置,提高性能的空间往往不大。这个时候就要考虑,语句本身是不是能够换一种方法实现。很多时候改一下语句,把一条大的语句拆分成若干条小的语句,或者去掉一些不必要的逻辑,会达到事半功倍的效果

在谈论如何做语句调优的具体方法之前,必须先介绍一下最必需的背景知识。不了解这些知识 ,做语句调优就只能基本靠猜。所需要的背景知识主要包括理解索引和统计信息,理解什么是统计和重编译,并且能够基本读懂语句的执行计划。以下为例子,借助MS示例数据库AdventureWordks来介绍。

--测试用例

USE AdventureWorks2008
GO
IF OBJECT_ID ('SalesOrderHeader_TEST') IS NOT NULL
DROP TABLE dbo.SalesOrderHeader_TEST
GO
IF OBJECT_ID ('dbo.SalesOrderDetail_TEST') IS NOT NULL
DROP TABLE dbo.SalesOrderDetail_TEST
GO -- (31465 行受影响) SELECT * INTO dbo.SalesOrderHeader_TEST
FROM Sales.SalesOrderHeader -- (121317 行受影响) SELECT * INTO dbo.SalesOrderDetail_TEST
FROM Sales.SalesOrderDetail -- 建立聚集索引
CREATE CLUSTERED INDEX SalesOrderHeader_TEST_CL ON dbo.SalesOrderHeader_TEST(SalesOrderID) -- 建立非聚集索引
CREATE NONCLUSTERED INDEX SalesOrderDetail_TEST_NCL ON dbo.SalesOrderDetail_test(SalesOrderID)
go

SalesOrderHeader_TEST 里存放的是每一张订单的头信息,包括订单创建日期、客户编号、合同编号、销售员编号等,每个订单都有一个单独的订单号。在订单号这个字段上,有一个聚集索引。
SalesOrderDetail_TEST 里存放的是订单的详细内容。一张订单可以销售多个产品给同一个客户,所以SalesOrderHeader_TEST 和SalesOrderDetail_TEST是一对多的关系。每每详细内容包括它所属的订单编号,它自己在表格里的唯一编号(SalesOrderDetailID)、产品编号、单价、以及销售数量等。在这里,先只在SalesOrderDetailID 上建立一个非聚集索引。
按照AdventureWorks里原先的数据, header_test 里面有3万多条订单信息,detail里有12万多条订单详细记录,基本上一条订单有3-5条详细记录。这是一个正常的分布。

下面再在 header_test 里面加入9条订单记录,他们的编号是从75124 到75132这是9张特殊的订单,每张有12万多条详细记录。也就是说 deatil_test里会有90%的数据属于这9张订单。

declare @i int
set @i = 1
while @i < 10
begin
INSERT INTO [AdventureWorks2008].[dbo].[SalesOrderHeader_TEST]
([RevisionNumber]
,[OrderDate]
,[DueDate]
,[ShipDate]
,[Status]
,[OnlineOrderFlag]
,[SalesOrderNumber]
,[PurchaseOrderNumber]
,[AccountNumber]
,[CustomerID]
,[SalesPersonID]
,[TerritoryID]
,[BillToAddressID]
,[ShipToAddressID]
,[ShipMethodID]
,[CreditCardID]
,[CreditCardApprovalCode]
,[CurrencyRateID]
,[SubTotal]
,[TaxAmt]
,[Freight]
,[TotalDue]
,[Comment]
,[rowguid]
,[ModifiedDate])
SELECT [RevisionNumber]
,[OrderDate]
,[DueDate]
,[ShipDate]
,[Status]
,[OnlineOrderFlag]
,[SalesOrderNumber]
,[PurchaseOrderNumber]
,[AccountNumber]
,[CustomerID]
,[SalesPersonID]
,[TerritoryID]
,[BillToAddressID]
,[ShipToAddressID]
,[ShipMethodID]
,[CreditCardID]
,[CreditCardApprovalCode]
,[CurrencyRateID]
,[SubTotal]
,[TaxAmt]
,[Freight]
,[TotalDue]
,[Comment]
,[rowguid]
,[ModifiedDate]
FROM [SalesOrderHeader_TEST] WHERE SalesOrderID = 75123 INSERT INTO [AdventureWorks2008].[dbo].[SalesOrderDetail_TEST]
([SalesOrderID]
,[CarrierTrackingNumber]
,[OrderQty]
,[ProductID]
,[SpecialOfferID]
,[UnitPrice]
,[UnitPriceDiscount]
,[LineTotal]
,[rowguid]
,[ModifiedDate])
SELECT 75123 + @i
,[CarrierTrackingNumber]
,[OrderQty]
,[ProductID]
,[SpecialOfferID]
,[UnitPrice]
,[UnitPriceDiscount]
,[LineTotal]
,[rowguid]
,GETDATE()
FROM Sales.SalesOrderDetail
SET @i = @i + 1
END
GO

SQL语句调优-基础知识准备的更多相关文章

  1. 语句调优基础知识-set statistics profile on

    set statistics profile on 获取语句真实的执行计划信息 set statistics profile on go select distinct Productid,unitp ...

  2. 语句调优基础知识-set statistics time on

    set statistics time on --清空缓存数据 dbcc dropcleanbuffers go --清空缓存计划 dbcc freeproccache go set statisti ...

  3. 语句调优基础知识-set statistics io on

    set statistics io on --清空缓存数据 dbcc dropcleanbuffers go --清空缓存计划 dbcc freeproccache go set statistics ...

  4. MySQL千万级多表关联SQL语句调优

    本文不涉及复杂的底层数据结构,通过explain解释SQL,并根据可能出现的情况,来做具体的优化.   需要优化的查询:使用explain      出现了Using temporary:       ...

  5. MySQL百万级、千万级数据多表关联SQL语句调优

    本文不涉及复杂的底层数据结构,通过explain解释SQL,并根据可能出现的情况,来做具体的优化,使百万级.千万级数据表关联查询第一页结果能在2秒内完成(真实业务告警系统优化结果).希望读者能够理解S ...

  6. SQL语句调优三板斧

    改装有顺序------常开的爱车下手 你的系统中有成千上万的语句,那么优化语句从何入手呢 ? 当然是系统中运行最频繁,最核心的语句了.废话不多说,上例子: 这是一天的语句执行情况,里面柱状图表示的是对 ...

  7. SQL性能调优基础教材

    一.数据库体系结构 1.       Oracle数据库和实例 数据库:物理操作系统文件或磁盘的集合. 实例:一组Oracle后台进程/线程以及一个共享内存区,这些内存由同一个计算机上运行的线程/进程 ...

  8. SQL语句调优相关方法

    SQL语句慢的原因:1,数据库表的统计信息不完整2,like查询估计不准确调优方法:1,查看表中数据的条数:2, explain analyze target_SQL;查看SQL执行计划:比较SQL总 ...

  9. 【初学Java学习笔记】SQL语句调优

    1, 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2,应尽量避免在 where 子句中对字段进行 null 值判断,创建表时NULL是默认 ...

随机推荐

  1. Yaf零基础学习总结3-Hello Yaf

    Yaf零基础学习总结3-Hello Yaf 上一次我们已经学习了如何安装yaf了,准备工作做好了之后我们来开始实际的编码了,码农都知道一个经典的语句就是“Hello World”了,今天我们开始入手Y ...

  2. ios9关闭系统自动更新

    链接:https://www.zhihu.com/question/37297197/answer/104363172 https://www.zhihu.com/question/37297197/ ...

  3. 《理解 ES6》阅读整理:函数(Functions)(一)Default Parameter Values

    对于任何语言来说,函数都是一个重要的组成部分.在ES6以前,从JavaScript被创建以来,函数一直没有大的改动,留下了一堆的问题和很微妙的行为,导致在JavaScript中使用函数时很容易出现错误 ...

  4. Cocoapods降低版本及卸载

    有的时候我们需要降低Cocoapods的版本来解决第三方库的兼容问题.   一. 移除pod组件 这条指令会告诉你Cocoapods组件装在哪里 :     1 $ which pod 你可以手动移除 ...

  5. 安装mysql数据库中的技巧、错误排查以及实用命令(持续更新)

    针对解压版本5.7.16(博主使用的这个版本.在某些低版本中部分命令失效) 一.初始化data目录(解压版解压后没有data目录) mysqld --initialize-insecure --use ...

  6. CSDN 分糖果算法的思路和求助

    昨天晚上 在csdn上做了一道分糖果的题目,我自个测的是没有问题,但是提交答案后,老失败,提示 你的程序正常运行并输出了结果,但是答案错误你的程序输出结果与测试数据中的输出结果不符 我先把自个思路说一 ...

  7. HTML5服务器端推送事件 解决PHP微信墙推送问题

    问题描述 以前的文章中<PHP微信墙制作,开源>已经用PHP搭建了一个微信墙获取信息的服务器,然后我就在想推送技术应该怎么解决,上一篇已经用了.NET 的signalr做了一个微信墙,PH ...

  8. C#设计模式(19)——状态者模式(State Pattern)

    一.引言 在上一篇文章介绍到可以使用状态者模式和观察者模式来解决中介者模式存在的问题,在本文中将首先通过一个银行账户的例子来解释状态者模式,通过这个例子使大家可以对状态者模式有一个清楚的认识,接着,再 ...

  9. Linux WAS7 启动异常

    启动server1异常,信息如下: [root@cmiecmceprd02 bin]# ./startServer.sh server1ADMU0116I: Tool information is b ...

  10. Nim教程【三】

    这是国内第一个关于Nim的系列教程 (至少我百度和必应是没有找到类似的教程) 先说废话 有人说 Golang的编译器/工具链也学互联网行业跟风拿用户当测试,简直一点素质没有. 还有人说 Go社区的风气 ...