技术开发 频道

十步优化SQL Server中的数据访问

  理解查询执行计划

  当你将SQL语句发给SQL Server引擎后,SQL Server首先要确定最合理的执行方法,查询优化器会使用很多信息,如数据分布统计,索引结构,元数据和其它信息,分析多种可能的执行计划,最后选择一个非常好的的执行计划。

  可以使用SQL Server Management Studio预览和分析执行计划,写好SQL语句后,点击SQL Server Management Studio上的评估执行计划按钮查看执行计划,如图1所示。

  图 1 在Management Studio中评估执行计划

  在执行计划图中的每个图标代表计划中的一个行为(操作),应从右到左阅读执行计划,每个行为都一个相对于总体执行成本(100%)的成本百分比。

  在上面的执行计划图中,右边的那个图标表示在HumanResources表上的一个“聚集索引扫描”操作(阅读表中所有主键索引值),需要100%的总体查询执行成本,图中左边那个图标表示一个select操作,它只需要0%的总体查询执行成本。

  下面是一些比较重要的图标及其对应的操作:

  图 2 常见的重要图标及对应的操作

  注意执行计划中的查询成本,如果说成本等于100%,那很可能在批处理中就只有这个查询,如果在一个查询窗口中有多个查询同时执行,那它们肯定有各自的成本百分比(小于100%)。

  如果想知道执行计划中每个操作详细情况,将鼠标指针移到对应的图标上即可,你会看到类似于下面的这样一个窗口。

  图 3 查看执行计划中行为(操作)的详细信息

  这个窗口提供了详细的评估信息,上图显示了聚集索引扫描的详细信息,它要查找AdventureWorks数据库HumanResources方案下Employee表中 Gender = ‘M’的行,它也显示了评估的I/O,CPU成本。

  查看执行计划时,我们应该获得什么信息

  当你的查询很慢时,你就应该看看预估的执行计划(当然也可以查看真实的执行计划),找出耗时最多的操作,注意观察以下成本通常较高的操作:

  1、表扫描(Table Scan)

  当表没有聚集索引时就会发生,这时只要创建聚集索引或重整索引一般都可以解决问题。

  2、聚集索引扫描(Clustered Index Scan)

  有时可以认为等同于表扫描,当某列上的非聚集索引无效时会发生,这时只要创建一个非聚集索引就ok了。

  3、哈希连接(Hash Join)

  当连接两个表的列没有被索引时会发生,只需在这些列上创建索引即可。

  4、嵌套循环(Nested Loops)

  当非聚集索引不包括select查询清单的列时会发生,只需要创建覆盖索引问题即可解决。

  5、RID查找(RID Lookup)

  当你有一个非聚集索引,但相同的表上却没有聚集索引时会发生,此时数据库引擎会使用行ID查找真实的行,这时一个代价高的操作,这时只要在该表上创建聚集索引即可。

  TSQL重构真实的故事

  只有解决了实际的问题后,知识才转变为价值。当我们检查应用程序性能时,发现一个存储过程比我们预期的执行得慢得多,在生产数据库中检索一个月的销售数据居然要50秒,下面就是这个存储过程的执行语句:

  exec uspGetSalesInfoForDateRange ‘1/1/2009’, 31/12/2009,’Cap’

  Tom受命来优化这个存储过程,下面是这个存储过程的代码:

 ALTER PROCEDURE uspGetSalesInfoForDateRange

  
@startYear DateTime,

  
@endYear DateTime,

  
@keyword nvarchar(50)

  
AS

  
BEGIN

  
SET NOCOUNT ON;

  
SELECT

  Name,

  ProductNumber,

  ProductRates.CurrentProductRate Rate,

  ProductRates.CurrentDiscount Discount,

  OrderQty Qty,

  dbo.ufnGetLineTotal(SalesOrderDetailID) Total,

  OrderDate,

  DetailedDescription

  
FROM

  Products
INNER JOIN OrderDetails

  
ON Products.ProductID = OrderDetails.ProductID

  
INNER JOIN Orders

  
ON Orders.SalesOrderID = OrderDetails.SalesOrderID

  
INNER JOIN ProductRates

  
ON

  Products.ProductID
= ProductRates.ProductID

  
WHERE

  OrderDate
between @startYear and @endYear

  
AND

  (

  ProductName
LIKE '' + @keyword + ' %' OR

  ProductName
LIKE '% ' + @keyword + ' ' + '%' OR

  ProductName
LIKE '% ' + @keyword + '%' OR

  Keyword
LIKE '' + @keyword + ' %' OR

  Keyword
LIKE '% ' + @keyword + ' ' + '%' OR

  Keyword
LIKE '% ' + @keyword + '%'

  )

  
ORDER BY

  ProductName

  
END

  
GO
2
相关文章