MS SQL Server 2005 物理查询处理中的各个阶段(二)
大家好,我是浪客,和大家分享一些最近我从《Microsoft SQL SERVER 2005技术内幕:T-SQL查询》书中的心得,终于出“二“了,回应很多朋友的需求,今天抽空写了物理查询阶段,
上文中你真的了解“T-SQL逻辑查询吗?”提到的这种搜索方式,也许很多人不明白(包括我,我看之前简直感到诧异),很多都想 如果表的记录有10000000~!#!@条,那每次的CROSS JOIN 将会长生 m*n的记录,我们就假设是1W条 1w的平方还是有点点恐怖的,所以实际存储引擎并不是如此查询的,但是讲清楚 逻辑查询很重要,因为那是物理查询的基础,我觉得 理解数据库引擎的查询处理方式有助于 开发人员在生产过程中做出正确的选择。PS:(有朋友说文章很多都“借鉴“别人的例子,我想是好东西用什么例子都不重要吧,只要能分享给大家,我抄都抄过来,再说是我对书的一些总结,呵呵~,这里要感谢作者Lubor Kollar,他是书中该章节的作者,是MS SQL SERVER 2005开发人员)。
那么开始吧,当一个查询你到达数据库引擎的时候 ,SQL SERVER 执行两个主要的步骤来产生结果,一步就是 “查询编译”,一个是“生成查询计划”。首先提一下为什么存储过程的效率总是比应用程序级别的T-SQL语句来的更迅速,首先抛开网络传输T-SQL语句的时间不管,我们利用应用程序发送的T-SQL语句,交个数据库执行,他首先就要对T-SQL语句进行编译,在SQL中编译的概念,和我们写应用程序理解应该是一致的,包括语法的检查,代数化以及查询优化,就像我们的应用程序(我是搞.NET的),编译器对你的C#代码进行编译,先检查语法的错误,然后生成dll,dll 中就包括对整个类库的描述类似于SQL中的执行计划,回到SQL中,这个编译过程当然是需要时间的,所以应用程序级别的T-SQL 交给数据库编译以后才执行,更可恶的是,竟然对外部传输来的T-SQL语句不会进行 “过程缓存”,因为他在编译后就立即执行了,而存储过程他就已经预先编译了,也进行了查询的优化了,还会保存在“过程缓存”中,所以推荐使用存储过程。
下面就来展示一个例子:
USE Northwind;
SELECT C.CustomerId,COUNT(o.OrderId) AS NumOrders
FROM dbo.Customers AS C
LEFT OUTER JOIN dbo.Orders AS o ON c.CustomerId=o.CustomerId
WHERE c.City='London'
GROUP BY C.CustomerId
HAVING COUNT(o.OrderId)>5
ORDER BY NumOrders;
返回结果:
EASTC 8
SEVES 9
BSBEV 10
AROUT 13
上次 就有朋友在留言中提到这个问题 ,下面我们来看看他的执行计划,到底 逻辑处理 和物理处理 有什么不同.我们点击 “显示估计的执行计划” ,然后找到 最右边的 Index seek 索引查找,下图
这是我切下来的图片,
我们看到 他的Seek 谓词 是 [Northwind].[dbo].[Customers].City=N’London’
再看看 我们的查询 语句的WHERE 部分
WHERE c.City='London'
完全 符合我在 你真的了解T-SQL逻辑查询吗? 一问中先说到的 第一个阶段 找到FROM 的表,但是又有一点不同,物理查询 他会等到执行CROSS 链接以后的 记录,他会先直接 筛选WHERE 中的记录 等于 讲 前3个 逻辑 处理阶段 的 连接和 第4个阶段WHERE 合并了.至于 这样有什么好处呢?
我们继续,首先我们分析 WHERE ,我们先考虑一种情况 如果 是按照 逻辑 执行阶段的顺序,CROSS JOIN 下来的 虚拟表 将是非常恐怖的 .可是 MS 的员工 在逻辑阶段 到物理阶段的过程中,肯定会采取一些列手段来优化T-SQL 语句,所以 我们联想到 先执行WHERE 中的 逻辑处理阶段 将 左表中的 结果 返回
相当于 执行:
USE Northwind;
SELECT C.CustomerId
FROM dbo.Customers AS C
WHERE c.City='London'
他返回的结果是:
AROUT
BSBEV
CONSH
EASTC
NORTS
SEVES
果然和我们 预想的一样返回的 行数 完全和执行计划中的 估计行数 : 6 行 吻合,
这样执行的结果的好处 ,我们自然可以联想到,将6行的结果集 再来 CROSS JOIN 就小多了
,下面我们继续刚才的分析,接着 自然是 Orders 表的链接,
自然 就
我们再回过来看看 之前说的 物理处理阶段,是不是 完全吻合. 之所以要说明白 逻辑阶段,(说个题外话,有兴趣的朋友可以去看看Algebrizer,他是T-SQL中的 新组件是 绑定的重要功能,我想对高数有研究的朋友可能会喜欢里面的研究和分析.他取代了2000中的Normalizer组件,在物理 逻辑 级别提高了T-SQL 效率.)
对于 后面文章的 优化查询语句 起到了 举足轻重的作用,在 讲明了 物理 处理阶段和 逻辑处理阶段 对于 存储引擎是 怎么执行T-SQL的 有了一定的了解,才能从原理级别去提高T-SQL ,这也是国内很多同行不曾重视的.当然本文的下一篇将继续我们的研究 -子查询的精要