奇忠诚 发表于 2015-6-27 11:25:05

SQL Server调优系列基础篇(子查询运算总结)

  前言
  前面我们的几篇文章介绍了一系列关于运算符的介绍,以及各个运算符的优化方式和技巧。其中涵盖:查看执行计划的方式、几种数据集常用的连接方式、联合运算符方式、并行运算符等一系列的我们常见的运算符。有兴趣的童鞋可以点击查看。
  本篇我们介绍关于子查询语句的一系列内容,子查询一般是我们形成复杂查询的一些基础性操作,所以关于子查询的应用方式就非常重要。
  废话少说,开始本篇的正题。
  技术准备
  数据库版本为SQL Server2008R2,利用微软的一个更简洁的案例库(Northwind)进行分析。
  一、独立的子查询方式
  所谓的独立的子查询方式,就是说子查询和主查询没有相关性,这样带来的好处就是子查询不依赖于外部查询,所以可以独立外部查询而被评估,形成自己的执行计划执行。
  举个例子



SELECT O1.OrderID,O1.Freight
FROM Orders O1
WHERE O1.Freight>
(
SELECT AVG(O2.Freight)
FROM Orders O2
)
  这句SQL执行的目标是查询订单中运费大于平均运费数的订单。
  这里提取平均运费的子句就是一个完全独立的子查询,完全不依赖主查询而独立执行。同时这里我们这里利用利用一个标量计算(AVG),因此正好返回一行。
  查看一下该语句的查询计划:

  这个查询计划没啥好介绍的,关于子查询的执行计划形成可以参照我的第二篇:SQL Server调优系列基础篇(常用运算符总结)
  不过这里需要提示一下就是,关于流聚合和计算标量形成的结果值(AVG)只包含一个结果值,所以该语句能正常的执行。
  
  我们再来看另外一种情况



SELECT O.OrderID
FROM Orders O
WHERE O.CustomerID=
(
SELECT C.CustomerID
FROM Customers C
WHERE C.ContactName=N'Maria Anders'
)
  该语句的也是获取名字为'Maria Anders'的顾客有多少订单。这句T-SQL语句能否执行的前提是在顾客表里存不存在同名的“'Maria Anders'”顾客,如果存在同名情况,该语句就不能正确执行,而如果恰巧只有一名顾客为'Maria Anders',则能正常执行。
  我们来分析一下对于这种执行的时候才能判断能否正确执行的SQL Server如何判断的

  在这里出现了一个新的运算符,名字是:断言。我们用文本执行计划来查看一下,这个运算符的主要功能是什么


  
  经过上面的分析,我们已经分析出了上面的“断言”运算符的作用,因为我们的子查询语句不能保证返回的结果为一行,所以,这里引入了一个断言运算符来做判断。
  所以,断言的作用就是根据下文的条件,判断子查询句的查询结果是否满足主语句的查询要求。
  如果,断言发现子语句不满足,就会直接报错,比如上面的Expr1005>1

  并且,断言运算符还经常用来检测其它条件是否满足,比如:约束条件、参数类型、值长度等。
  其实,这里断言要解决的问题就是判断我们的筛选条件中ContactName中的值是否存在重复值的,对于这种判断相对性能消耗还是比较小的,有时候对于别的复杂的断言操作需要消耗大量资源,所以我们就可以根据适当情况情况避免断言操作。
  比如,上面的语句我们可以明确的告诉SQL Server在表Customers中ContactName列就不存在重复值,它就不需要断言了。我们在上面建立一个:唯一、非聚集索引实现



CREATE UNIQUE INDEX ContactNameIndex ON Customers(ContactName)
GO
SELECT O.OrderID
FROM Orders O
WHERE O.CustomerID=
(
SELECT C.CustomerID
FROM Customers C
WHERE C.ContactName=N'Maria Anders'
)
drop index Customers.ContactNameIndex
GO

  经过我们唯一非聚集索引的提示,SQL Server已经明确的知道我们的子查询语句不会返回多行的情况,所以就去掉了断言操作。
  
  二、相关的子查询方式
  相比上面的独立子查询方式,这里的相关的子查询方式相对复杂点,就是我们的子查询依赖于主查询的的结果,对于这种子查询就不能单独执行。
  我们来看个这样的子查询例子



SELECT O1.OrderID
FROM Orders O1
WHERE O1.Freight>
(
SELECT AVG(O2.Freight)
FROM Orders O2
WHERE O2.OrderDate
页: [1]
查看完整版本: SQL Server调优系列基础篇(子查询运算总结)