深入SQL语句性能调整(二)

日期: 2008-12-03 来源:TechTarget中国 英文


  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 的画面

  深如SQL语句性能调整(图三)

   图 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)」等功能,而且执行性能极佳。

      深入SQL语句性能调整(图四)
   图 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 编号

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

相关推荐