SELECT语句逻辑执行顺序 你知道吗?

引言

  这不是一个什么多深的技术问题,多么牛叉的编程能力。这跟一个人的开发能力也没有非常必然的直接关系,但是知道这些会对你的SQL编写,排忧及优化上会有很大的帮助。它不是一个复杂的知识点,但是一个非常基础的SQL根基。不了解这些,你一直用普通水泥盖房子;掌握这些,你是在用高等水泥盖房子。

  然而,就是这么一个小小的知识点,大家可以去调查一下周围的同事朋友,没准你会得到一个“惊喜”。

  由于这篇文章是突然有感而写,下面随手编写的SQL语句没有经过测试。

  看下面的几段SQL语句:

1
2
3
4
5
6
7
SELECT ID, COUNT (ID) AS TOTAL
 
FROM STUDENT
 
GROUP BY ID
 
HAVING TOTAL>2
1
2
3
4
5
6
7
SELECT ID, COUNT (ID) AS TOTAL
 
FROM STUDENT
 
GROUP BY ID
 
ORDER BY TOTAL
1
2
3
4
5
SELECT FIRSTNAME+ ' ' +LASTNAME AS NAME , COUNT (*) AS COUNT
 
FROM STUDENT
 
GROUP BY NAME

  你觉得哪一个不能够成功执行?

 言归正传

  下面是SELECT语句的逻辑执行顺序:

  1. FROM
  2. ON
  3. JOIN
  4. WHERE
  5. GROUP BY
  6. WITH CUBE or WITH ROLLUP
  7. HAVING
  8. SELECT
  9. DISTINCT
  10. ORDER BY
  11. TOP

  MICROSOFT指出,SELECT语句的实际物理执行顺序可能会由于查询处理器的不同而与这个顺序有所出入。

 几个示例

  示例一

1
2
3
4
5
6
7
SELECT ID, COUNT (ID) AS TOTAL
 
FROM STUDENT
 
GROUP BY ID
 
HAVING TOTAL>2

  觉得这个SQL语句眼熟吗?对,非常基础的分组查询。但它不能执行成功,因为HAVING的执行顺序在SELECT之上。

  实际执行顺序如下:

  1. FROM STUDENT
  2. GROUP BY ID
  3. HAVING TOTAL>2
  4. SELECT ID,COUNT(ID) AS TOTAL

  很明显,TOTAL是在最后一句SELECT ID,COUNT(ID) AS TOTAL执行过后生成的新别名。因此,在HAVING TOTAL>2执行时是不能识别TOTAL的。

  示例二

1
2
3
4
5
6
7
SELECT ID, COUNT (ID) AS TOTAL
 
FROM STUDENT
 
GROUP BY ID
 
ORDER BY TOTAL

  这个的实际执行顺序是:

  1. FROM STUDENT
  2. GROUP BY ID
  3. SELECT ID,COUNT(ID) AS TOTAL
  4. ORDER BY TOTAL

  这一次没有任何问题,能够成功执行。如果把ORDER BY TOTAL换成ORDER BY COUNT(ID)呢?

1
2
3
4
5
6
7
SELECT ID, COUNT (ID) AS TOTAL
 
FROM STUDENT
 
GROUP BY ID
 
ORDER BY COUNT (ID)

  实际执行顺序:

  1. FROM STUDENT
  2. GROUP BY ID
  3. SELECT ID,COUNT(ID) AS TOTAL
  4. ORDER BY COUNT(ID)

  没错,它是能够成功执行的,看SQL执行计划,它与上面ORDER BY TOTAL是一样的。ORDER BY 是在SELECT后执行,因此可以用别名TOTAL。

  示例三

1
2
3
4
5
SELECT FIRSTNAME+ ' ' +LASTNAME AS NAME , COUNT (*) AS COUNT
 
FROM STUDENT
 
GROUP BY NAME

  实际执行顺序:

1
2
3
4
5
FROM STUDENT
 
GROUP BY NAME
 
SELECT FIRSTNAME+ ' ' +LASTNAME AS NAME , COUNT (*) AS COUNT

  很明显,执行GROUP BY NAME时别名NAME还没有创建,因此它是不能执行成功的。


注:步骤10,按ORDER BY子句中的列列表排序上步返回的行,返回游标VC10.这一步是第一步也是唯一一步可以使用SELECT列表中的列别名的步骤。这一步不同于其它步骤的 是,它不返回有效的表,而是返回一个游标。SQL是基于集合理论的。集合不会预先对它的行排序,它只是成员的逻辑集合,成员的顺序无关紧要。对表进行排序 的查询可以返回一个对象,包含按特定物理顺序组织的行。ANSI把这种对象称为游标。理解这一步是正确理解SQL的基础。

因为这一步不返回表(而是返回游标),使用了ORDER BY子句的查询不能用作表表达式。表表达式包括:视图、内联表值函数、子查询、派生表和共用表达式。它的结果必须返回给期望得到物理记录的客户端应用程序。例如,下面的派生表查询无效,并产生一个错误:

select * 
from(select orderid,customerid from orders order by orderid)
as d

下面的视图也会产生错误

create view my_view
as
select
*
from orders
order by orderid

      在SQL中,表表达式中不允许使用带有ORDER BY子句的查询,而在T—SQL中却有一个例外(应用TOP选项)。

      所以要记住,不要为表中的行假设任何特定的顺序。换句话说,除非你确定要有序行,否则不要指定ORDER BY 子句。排序是需要成本的,SQL Server需要执行有序索引扫描或使用排序运行符。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值