SQL语句的执行顺序

原文:http://www.cnblogs.com/huminxxl/p/3149097.html

查询语句中select from where group by having order by的执行顺序
 
1.查询中用到的关键词主要包含六个,并且他们的顺序依次为 
select--from--where--group by--having--order by 
 
其中select和from是必须的,其他关键词是可选的,这六个关键词的执行顺序 
与sql语句的书写顺序并不是一样的,而是按照下面的顺序来执行 
from--where--group by--having--select--order by, 
from:需要从哪个数据表检索数据 
where:过滤表中数据的条件 
group by:如何将上面过滤出的数据分组 
having:对上面已经分组的数据进行过滤的条件  
select:查看结果集中的哪个列,或列的计算结果 
order by :按照什么样的顺序来查看返回的数据 
 
2.from后面的表关联,是自右向左解析的 
而where条件的解析顺序是自下而上的。 
 
也就是说,在写SQL文的时候,尽量把数据量大的表放在最右边来进行关联, 
而把能筛选出大量数据的条件放在where语句的最下面。
 
 
SQL Select语句完整的执行顺序【从DBMS使用者角度】: 
  1、from子句组装来自不同数据源的数据; 
  2、where子句基于指定的条件对记录行进行筛选; 
  3、group by子句将数据划分为多个分组; 
  4、使用聚集函数进行计算; 
  5、使用having子句筛选分组; 
  6、计算所有的表达式; 
  7、使用order by对结果集进行排序。 

SQL Select语句的执行步骤【从DBMS实现者角度,这个对我们用户意义不大】: 
  1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义。 
  2) 语义分析,检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限。 
  3)视图转换,将涉及视图的查询语句转换为相应的对基表查询语句。 
  4)表达式转换, 将复杂的 SQL 表达式转换为较简单的等效连接表达式。 
  5)选择优化器,不同的优化器一般产生不同的“执行计划” 
  6)选择连接方式, ORACLE 有三种连接方式,对多表连接 ORACLE 可选择适当的连接方式。 
  7)选择连接顺序, 对多表连接 ORACLE 选择哪一对表先连接,选择这两表中哪个表做为源数据表。 
  8)选择数据的搜索路径,根据以上条件选择合适的数据搜索路径,如是选用全表搜索还是利用索引或是其他的方式。 
  9)运行“执行计划”。 
 
 
 
 

from 子句--执行顺序为从后往前、从右到左
表名(最后面的那个表名为驱动表,执行顺序为从后往前, 所以数据量较少的表尽量放后)

oracle 的解析器按照从右到左的顺序处理,FROM 子句中的表名,FROM 子句中写在最后的表(基础表 driving table)将被最先处理,即最后的表为驱动表,在FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3 个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指被其他表所引用的表

多表连接时,使用表的别名并把别名前缀于每个Column上。可以减少解析的时间并减少那些由Column 歧义引起的语法错误.

 

where子句--执行顺序为自下而上、从右到左

ORACLE 采用自下而上从右到左的顺序解析Where 子句,根据这个原理,表之间的连接必须写在其他Where 条件之前, 可以过滤掉最大数量记录的条件必须写在Where 子句的末尾。

group by--执行顺序从左往右分组

提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉。即在GROUP BY前使用WHERE来过虑,而尽量避免GROUP BY后再HAVING过滤。

having 子句----很耗资源,尽量少用

避免使用HAVING 子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作.

如果能通过Where 子句在GROUP BY前限制记录的数目,那就能减少这方面的开销.
(非oracle 中)on、where、having 这三个都可以加条件的子句中,on 是最先执行,where 次之,having 最后,因为on 是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,

where 也应该比having 快点的,因为它过滤数据后才进行sum,在两个表联接时才用on 的,所以在一个表的时候,就剩下where 跟having比较了。

在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where 可以使用rushmore 技术,而having 就不能,在速度上后者要慢。
如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,where 的作用时间是在计算之前就完成的,而having 就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。

在多表联接查询时,on 比where 更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where 进行过滤,然后再计算,计算完后再由having 进行过滤。

由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。

 


select子句--少用*号,尽量取字段名称

ORACLE 在解析的过程中, 会将依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 使用列名意味着将减少消耗时间。

sql 语句用大写的;因为 oracle 总是先解析 sql 语句,把小写的字母转换成大写的再执行

 


order by子句--执行顺序为从左到右排序,很耗资源

<think>嗯,用户想了解SQL查询的执行顺序,这个问题挺常见的。我得先回忆一下SQL的各个子句的执行顺序,可能和书写顺序不一样对吧。比如SELECT虽然写在最前面,但执行的时候可能比较靠后。 首先,我应该先列出各个子句的执行步骤。比如FROM和JOIN先执行,然后是WHERE、GROUP BY、HAVING,接着是窗口函数,再是SELECT,之后是DISTINCT、ORDER BY,最后是LIMIT。需要确认一下顺序是否正确,有没有遗漏的地方。 接下来,可能需要用一个具体的例子来说明这个过程。比如用户给一个查询的例子,分解每个步骤会发生什么。比如FROM先确定表,JOIN连接其他表,WHERE过滤行,GROUP BY分组,HAVING过滤分组后的结果,然后处理窗口函数,接着SELECT选择字段,DISTINCT去重,ORDER BY排序,最后LIMIT限制结果数量。 要注意的是,用户可能容易混淆书写顺序执行顺序,尤其是SELECT在GROUP BY之前写,但执行却在后面。这时候需要解释清楚执行顺序的不同,以及为什么在WHERE中不能使用SELECT的别名,因为那时候别名还没被处理。 另外,用户可能对窗口函数的执行位置不太清楚,需要指出窗口函数是在GROUP BY之后,SELECT之前执行的。这样他们就能明白为什么可以在窗口函数中使用聚合后的结果。 还要考虑用户的实际应用场景,比如在优化查询性能时,了解执行顺序有助于减少数据量,尽早过滤数据。比如先做WHERE再JOIN可能比反过来更高效,但这也取决于具体的数据库优化器。 最后,总结一下各个步骤,确保结构清晰,让用户能一步步理解整个过程。可能还需要提醒他们注意不同数据库系统的细微差别,但大体顺序是一致的。</think>SQL查询的执行顺序与实际书写顺序不同,理解这一点对编写高效查询和排查错误至关重要。以下是标准SQL查询的逻辑执行顺序(注意:实际数据库可能优化执行顺序,但逻辑结果一致): --- ### **1. 执行顺序分解** **按以下步骤逐步执行**: ``` 1. FROM 和 JOIN → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. 窗口函数 → 6. SELECT → 7. DISTINCT → 8. ORDER BY → 9. LIMIT/OFFSET ``` --- ### **2. 分步骤详解** #### **(1) FROM 和 JOIN** ```sql FROM table1 JOIN table2 ON condition ``` - **作用**:确定数据来源,生成虚拟表(包括笛卡尔积和连接筛选)。 - **优先级**:先执行FROM,再按左到右顺序处理JOIN。 #### **(2) WHERE** ```sql WHERE condition ``` - **作用**:过滤不符合条件的行(此时无法使用SELECT中的别名)。 - **注意**:WHERE在聚合前执行,因此不能包含聚合函数(如SUM、COUNT)。 #### **(3) GROUP BY** ```sql GROUP BY column1, column2 ``` - **作用**:按指定列分组,生成分组后的虚拟表。 - **常见错误**:SELECT中的非聚合列未包含在GROUP BY中。 #### **(4) HAVING** ```sql HAVING condition ``` - **作用**:对分组后的结果进行过滤(可包含聚合函数,如`HAVING SUM(price) > 100`)。 #### **(5) 窗口函数(如ROW_NUMBER)** ```sql ROW_NUMBER() OVER (PARTITION BY column ORDER BY column) ``` - **作用**:在分组聚合后计算,但早于SELECT执行。 #### **(6) SELECT** ```sql SELECT column1, SUM(column2) AS total ``` - **作用**:选择最终输出的列,计算表达式和别名。 - **关键点**:此时才生成SELECT列表中的别名(因此WHERE中无法使用别名)。 #### **(7) DISTINCT** ```sql SELECT DISTINCT column1 ``` - **作用**:去重操作,基于SELECT后的结果。 #### **(8) ORDER BY** ```sql ORDER BY column1 DESC ``` - **作用**:排序最终结果(可使用SELECT中的别名)。 #### **(9) LIMIT/OFFSET** ```sql LIMIT 10 OFFSET 5 ``` - **作用**:限制返回行数,最后执行。 --- ### **3. 示例分析** #### **原始查询**: ```sql SELECT department, AVG(salary) AS avg_salary FROM employees JOIN departments ON employees.dept_id = departments.id WHERE hire_date > '2020-01-01' GROUP BY department HAVING AVG(salary) > 5000 ORDER BY avg_salary DESC LIMIT 3; ``` #### **实际执行步骤**: 1. **FROM + JOIN**:合并`employees`和`departments`表。 2. **WHERE**:过滤`hire_date > '2020-01-01'`的员工。 3. **GROUP BY**:按`department`分组。 4. **HAVING**:筛选平均工资超过5000的部门。 5. **SELECT**:计算`AVG(salary)`并命名为`avg_salary`。 6. **ORDER BY**:按`avg_salary`降序排序。 7. **LIMIT**:取前3条结果。 --- ### **4. 关键总结** - **别名限制**:WHERE中不能使用SELECT定义的别名(因为WHERE早于SELECT执行)。 - **聚合顺序**:WHERE处理行级过滤 → GROUP BY聚合 → HAVING过滤聚合结果。 - **性能优化**:尽量在早期步骤(如WHERE)减少数据量。 理解此顺序可避免语法错误,并帮助优化复杂查询! 🚀
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值