欢迎投稿

今日深度:

SQL高手进阶 深入SQL语句性能调整(1)(2)

4、避免在 WHERE 子句中对字段使用函数

对字段使用函数,也等于对字段做运算或串接的动作,一样可能会让「查询最佳化程序」无法有效地使用索引。但真正对性能影响最重大的,是当您的数据表内若有 10 万笔数据,则在查询时就需要呼叫函数 10 万次,这点才是真正的性能杀手。程序员应注意,在系统开发初期可能感觉不出差异,但当系统上线且数据持续累积后,这些语法细节所造成的性能问题就会逐步浮现。

SELECT * FROM Orders WHERE DATEPART(yyyy, OrderDate) = 1996 AND DATEPART(mm, OrderDate)=7

可改成

SELECT * FROM Orders WHERE OrderDate BETWEEN '19960701' AND '19960731'

SELECT * FROM Orders WHERE SUBSTRING(CustomerID, 1, 1) = 'D'

可改成

SELECT * FROM Orders WHERE CustomerID LIKE 'D%'

注意当您在下 UPDATE、DELETE 语句时,若有采用 WHERE 子句,也应符合上述原则。

5、AND 与 OR 的使用

在 AND 运算中,「只要有一个」条件有用到索引 (如下方的 CustomerID),即可大幅提升查询速度,如下图 3 所示:

SELECT * FROM Orders WHERE CustomerID='VINET' AND Freight=32.3800 --使用索引,会出现下图 3 的画面

SELECT * FROM Orders WHERE Freight=32.3800 --不使用索引,会出现上图 2 的画面

 图 3

但在 OR 运算中,则要「所有的」条件都有可用的索引,才能使用索引来提升查询速度。因此 OR 运算符的使用必须特别小心。

若您将上方 AND 的范例,逻辑运算符改成 OR 的话,如下所示:

SELECT * FROM Orders WHERE CustomerID='VINET' OR Freight=32.3800

由于无法有效地使用索引,也会出现图 2 的画面。

在使用 OR 运算符时,只要有一个条件 (字段) 没有可用的索引,则其它所有的条件 (字段) 都有索引也没用,只能如图 2 般,把整个数据表或整个集簇索引都扫描过,以逐笔比对是否有符合条件的数据。

据网络上文件的说法 [1],上述的 OR 运算语句,我们还可用 UNION 联集适当地改善,如下:

SELECT * FROM Orders WHERE CustomerID='VINET'

UNION

SELECT * FROM Orders WHERE Freight=32.3800

此时您再按 Ctrl + L 检阅「执行计划」,会发现上半段的查询会使用索引,但下半段仍用集簇索引扫描,对性能不无小补。

6、适当地使用子查询

相较于「子查询 (Subquery)」,若能用 JOIN 完成的查询,一般会比较建议使用后者。原因除了 JOIN 的语法较容易理解外,在多数的情况下,JOIN 的性能也会比子查询较佳;但这并非绝对,也有的情况可能刚好相反。

我们知道子查询可分为「独立子查询」和「关联子查询」两种,前者指子查询的内容可单独执行,后者则无法单独执行,亦即外层查询的「每一次」查询动作都需要引用内层查询的数据,或内层查询的「每一次」查询动作都需要参考外层查询的数据。

以下我们看一个比较极端的例子 [2]。若我们希望所有查询出来的数据,都能另外给一个自动编号,版工我在之前的文章「ASP.NET 数据分页第一篇 - 探讨分页原理及 SQL Server 2005 的 ROW_NUMBER 函数」中有介绍过,可用 SQL Server 2005 中新增的 ROW_NUMBER 函数轻易地达成,且 ROW_NUMBER 函数还能再加上「分群 (PARTITION BY)」等功能,而且执行性能极佳。

 图 4

将 Orders 数据表的 830 笔数据都捞出来,并在右侧给一组自动编号

现在我们要如上图 4 般,将 Northwind 数据库中 Orders 数据表的 830 笔数据都捞出来,并自动给一组编号,若用 ROW_NUMBER 函数的写法如下所示,而且性能极佳,只要 2 ms (毫秒),亦即千分之二秒。

SET STATISTICS TIME ON

SELECT OrderID, ROW_NUMBER() OVER(ORDER BY OrderID) AS 编号

FROM dbo.Orders

但如果是传统的「子查询」写法,或 辅以 AS 关键词的「衍生数据表」的语法,写法必须如下 (拷贝后在 SQL Server 中实际可执行):

SET STATISTICS TIME ON

SELECT OrderID,

(SELECT COUNT(*) FROM dbo.Orders AS 内圈

WHERE 内圈.OrderID <= 外圈.OrderID) AS 编号

FROM dbo.Orders AS 外圈

ORDER BY 编号


www.htsjk.Com true http://www.htsjk.com/shujukujc/19156.html NewsArticle 4、避免在 WHERE 子句中对字段使用函数 对字段使用函数,也等于对字段做运算或串接的动作,一样可能会让「查询最佳化程序」无法有效地使用索引。但真...
评论暂时关闭