图35-22 执行中的追踪
最佳化执行计划
修改执行计划是相当困难的,要建立一个比 Query Optimizer 的计划更佳的执行计划更不容易。有些操作更可能在执行计划的修改中获益,它们是 JOIN、GROUP BY、ORDER BY 和 UNION。对于这些操作的修改可以容易的透过使用提示来达成,这将在稍后的 <使用提示> 一节中提到。透过更改提示和显示 Query Analyzer 的输出,可以看到获得了一个比较有效的操作。
不过,对于最佳化 T-SQL 陈述式并没有一个特定的模式。因为每个数据库都是独一无二的,且应用程序也不相同,因此修改皆根据不同的情况进行。
选择数据存取方法
正如本章前面所述,数据存取方法实际上就是一组对象,SQL Server 使用这些对象从数据库中获得数据。透过分析数据库和数据库中包含的数据,可以最佳化数据存取方法,减少 I/O 操作的数量。
和修改执行计划一样,修改最佳的数据存取方法也没有一定的公式。下面的指导方针有助于选择最佳的数据存取方法:
• 使用最佳的索引 为一个操作使用最佳的索引,这在获得可能的最佳效能时是必须的。对于特定操作的最佳索引是最快速的找到数据,且最少 I/O 操作的一种方法。可以利用您对数据库和数据的深入了解或使用 Query Analyzer 来确认最佳的索引。Query Analyzer 让您尝试不同的模拟状况以确定哪个索引可以传回最少的列数。(记住,Query Analyzer 只是简单的估计了所要传回的列数;要确定精确的列数,必须使用 Profiler。)
________________________________________
说明
正如 第 17 章 所提到的,索引对于 SQL Server 有很大的好处,但是如果使用不正确,可能会反过来影响效能。监控每个数据表的索引数目,特别是在执行了很多 INSERT、UPDATE 和 DELETE 陈述式操作的时候。太多的索引可能会导致这种类型操作的效能降低,这是由于修改索引的额外系统资源占用所引起的效能降低。
________________________________________
• 使用覆盖式索引 (covering indexes) 正如 第 17 章 所述,使用覆盖式索引可以帮助您避免额外的 I/O 步骤。不必存取底层数据表,您可以从索引中获得所需的数据。
• 减少传回的数据列 决定是否需要从查询传回实际需要的所有数据。修改T-SQ L陈述式,以便于只存取需要存取的数据,不要传回将被丢弃的资料列。减少从数据库中获得的数据列,这可以透过增加查询的选择性来达成。
使用提示
可以修改 T-SQL 陈述式来更改资料存取方法和执行计划,但是如果执行时不够不谨慎,反而会变更 T-SQL 陈述式的功能。较安全的最佳化 T-SQL 陈述式的方法是使用提示。提示可指定 Query Optimizer 要执行哪些操作和需要使用哪些对象。在本节中,将学习很多不同的 SQL Server 提示,以及它们的使用方法。
联结提示
联结提示(join hints)是用来指定 Query Optimizer 应该执行哪些类型的联结操作。(如果在查询中没有指定类型,query optimizer 会自己选一个。)在 SQL Server 中,您可以执行巢状循环联结(nested loops joins)、杂凑联结(hash joins)、合并联结(merge joins)和远程联结(remote joins)。使用下列提示指定联结的方法:
• LOOP 指定巢状循环联结。在巢状循环联结中,将会检查外部数据表中的每一列和内部数据表中的每一列,检查值是否相等。
• HASH 指定杂凑联结。在杂凑联结中,一个数据表会被重新组织为一个杂凑数据表。其它的数据表每次被扫描一列,杂凑函数就被用来搜寻相同的内容。
• MERGE 指定一个排序合并联结。在排序合并联结中,每个数据表都被排序,然后按照降序每次比较一列。
• REMOTE 指定远程联结。远程联结是至少有一个联结的数据表在远程。
看看连结提示的范例,使用我们前面的范例(请参阅本章中的 <联结操作> 一节),我们按照下列陈述式使用提示来指定一个杂凑联结:
SELECT OrderID, CustomerID, Employees.EmployeeID, FirstName,
LastName, OrderDate
FROM Orders, Employees
WHERE Orders.EmployeeID = Employees.EmployeeID
OPTION (HASH JOIN)
________________________________________
说明
联结提示是彼此独立的-每次只能使用其中的一种。
________________________________________
如果选择使用 SQL-92 语法作为连结,您也能用提示来指定连结类型。使用SQL-92 语法,您可以重写之前的查询,如下:
SELECT OrderID, CustomerID, Employees.EmployeeID, Firstname,
LastName, OrderDate
FROM Orders INNER HASH JOIN Employees
ON (Orders.EmployeeID = Employees.EmployeeID)
联结提示是进阶的主题,我们并不能提供使用的经验方法。有很多不同的选择特殊联结操作的原因,例如同等运算子的数目、在联结中每个数据表的大小,以及联结的多少数据表。有一种最佳的途径可以确定更改联结操作是否将提供额外的效能,就是在 Query Analyzer 中尝试每一种类型的联结,看看哪种可以提供最小的消耗。当然,Query Optimize r通常会为帮助选择最佳的联结操作。
查询提示
查询提示(query hints)用来指定如何执行特定的查询操作。可用的查询操作分为三类:分组(group by)、联合(union)和混杂(miscellaneous)。
分组提示 下面的提示指定了如何执行 GROUP BY 或 COMPUTE 操作:
• HASH GROUP BY 指定使用杂凑函数来执行 GROUP BY 操作。
• ORDER GROUP BY 指定使用排序操作来执行 GROUP BY 操作。
使用前面的 GROUP BY 范例(请参阅本章的 <检视总计操作> 一节),您可以按照下面使用提示来指定如何执行 HASH GROUP BY 操作:
SELECT CustomerID, SUM(OrderDetails.UnitPrice)
FROM Orders, OrderDetails
HASH GROUP BY CustomerID
OPTION(HASH GROUP)
________________________________________
说明
GROUP BY 提示彼此独立-每次只能使用其中一种。
________________________________________
联合提示 下面的提示是用来指定如何执行 UNION 操作:
• MERGE UNION 使用合并操作来执行 UNION。
• HASH UNION 使用杂凑函数来执行 UNION。
• CONCAT UNION 使用串联功能来执行 UNION。
这是一个使用 CONCAT UNION 提示的范例:
SELECT OrderID, CustomerID, EmployeeID, OrderDATE
FROM orders
WHERE CustomerID = 'TOMSP'
UNION
SELECT OrderID, CustomerID, EmployeeID, OrderDate
FROM orders
WHERE EmployeeID = '4'
OPTION (CONCAT UNION)
________________________________________
说明
UNION 提示也是彼此独立的。
________________________________________
不幸的是,没有任何一定的公式可用以确定哪种 UNION 操作在您的环境中执行的最好。再一次说明,最好的途径就是使用 Query Analyzer 来尝试不同的 UNION 提示,看看哪种可以提供最少的消耗。通常 SQL Server Query Optimizer 可以为 UNION 提示决定最佳策略。
杂项提示 下面的提示可以用来执行多种的查询操作:
• FORCE ORDER 强制查询按照查询中数据表出现的次序执行。在预设状态下,SQL Server 可以重新排序数据表存取。
• ROBUST PLAN 强制 Query Optimizer 预备取得最有可能的最大数据列数。
以下是使用这个提示的范例:
SELECT OrderID, CustomerID, Employees.EmployeeID, FirstName,
LastName, OrderDate
FROM Orders, Employees
WHERE Orders.EmployeeID = Employees.EmployeeID
OPTION (ROBUST PLAN)
资料表提示
数据表提示 (table hints)用来控制数据表存取,两种数据表提示如下:
• FAST n 替代 FASTFIRSTROWS,用来保持向后的兼容性。最佳化查询以获得最前面n列的数据。
• INDEX=index_name 强制 Query Optimizer 在可能时使用指定的索引。在本章中的前面的范例之一示范了如