前几天,在想一个SQL的执行计划时,问了郑隐师兄,结果被反问了。现在看来,看似较难的问题,只要仔细思考都会回到一个很基础的知识点。
SQL的处理阶段:
SQL 的处理阶段会包括:解析、优化、产生行源和执行。当然并不是所有Oracle数据库都会这些处理,这得结合具体的SQL语句。
SQL的第一阶段:解析
这一阶段会将SQL语句的各个片段,分离到由其他进程处理的数据结构,当Oracle数据库得到应用程序的指示下,就会对下一个语句进行解析,这就意味着减少解析数目的不是Oracle数据库本身,而是应用程序。
当应用程序发出SQL语句时,该应用程序就会向数据库发出一个解析调用,用来准备执行该语句。解析调用会打开或者创建一个游标,其中包含了已分析的SQL语句的处理信息。在解析调用时,Oracle数据库会执行以下检查:
SQL执行第二阶段:优化
实际上Oracle数据库对查询的优化,是在统计收集数据的执行信息,这些信息来包括使用行数,数据集大小等,利用这些信息来生产各种可能的执行计划,并为每个计划分配一个成本值,这时候Oracle数据库就会具有最低成本的技术(CBO)
PS:提个问题 为什么DDL永远不会被优化,而DML语句必须执行一次硬解析?
SQL执行的第三阶段:行源生成
行源生成是数据库的一个软件产生的计划过程,它从优化器收集到已经优化的执行计划,并生成一个查询计划的迭代计划,用于生成结果集。行源生成会生成一个行源树,他是一个行源的集合,是执行计划中的某一步骤返回的行集结果
例如:
SELECT /*+gather_plan_statistics test12*/ T.METER_ID "[dianneng]" FROM MPAC.D_METER T LEFT JOIN (SELECT M.EQUIP_ID,
M.CONC_CODE, ROW_NUMBER() OVER(PARTITION BY EQUIP_ID ORDER BY DETECT_DATE DESC) RN FROM (SELECT
T1.EQUIP_ID,T1.CONC_CODE,T1.DETECT_DATE FROM MPAC.T_DETECT_MET_RSLT T1 UNION ALL SELECT
T2.EQUIP_ID,T2.CONC_CODE,T2.DETECT_DATE FROM MPAC.T_SAMPLING_MET_RSLT T2 UNION ALL SELECT
T3.EQUIP_ID,T3.CONC_CODE,T3.DETECT_DATE FROM MPAC.T_COMPARE_MET_RSLT T3) M) TR ON T.METER_ID = TR.EQUIP_ID AND TR.RN=1
WHERE T.STATUS_CODE = '017' AND T.SORT_CODE='10' AND (TR.CONC_CODE='02' OR TR.CONC_CODE IS NULL) AND T.PR_CODE='1'
Execution Plan
----------------------------------------------------------
Plan hash value: 1888591727
--------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1687 | 74228 | | 23874 (1)| 00:04:47 | | |
|* 1 | HASH JOIN OUTER | | 1687 | 74228 | | 23874 (1)| 00:04:47 | | |
|* 2 | TABLE ACCESS BY GLOBAL INDEX ROWID | D_METER | 1687 | 30366 | | 240 (1)| 00:00:03 | ROWID | ROWID |
|* 3 | INDEX RANGE SCAN | IDX_D_METER06048 | 4358 | | | 8 (0)| 00:00:01 | | |
|* 4 | VIEW | | 572K| 14M| | 23627 (1)| 00:04:44 | | |
|* 5 | WINDOW SORT PUSHED RANK | | 572K| 12M| 17M| 23627 (1)| 00:04:44 | | |
| 6 | VIEW | | 572K| 12M| | 19774 (1)| 00:03:58 | | |
| 7 | UNION-ALL | | | | | | | | |
| 8 | TABLE ACCESS BY GLOBAL INDEX ROWID| T_DETECT_MET_RSLT | 570K| 10M| | 16851 (1)| 00:03:23 | ROWID | ROWID |
|* 9 | INDEX RANGE SCAN | IDX_T_DETECT_MET_RSLT_04 | 570K| | | 1040 (1)| 00:00:13 | | |
|* 10 | TABLE ACCESS FULL | T_SAMPLING_MET_RSLT | 2052 | 43092 | | 2903 (1)| 00:00:35 | | |
|* 11 | TABLE ACCESS FULL | T_COMPARE_MET_RSLT | 387 | 7353 | | 19 (0)| 00:00:01 | | |
--------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T"."METER_ID"="TR"."EQUIP_ID"(+))
2 - filter("T"."SORT_CODE"='10' AND "T"."PR_CODE"='1')
3 - access("T"."STATUS_CODE"='017')
4 - filter("TR"."RN"(+)=1)
5 - filter(ROW_NUMBER() OVER ( PARTITION BY "EQUIP_ID" ORDER BY INTERNAL_FUNCTION("DETECT_DATE") DESC )<=1)
9 - access("CONC_CODE"='02')
10 - filter("CONC_CODE"='02')
11 - filter("CONC_CODE"='02')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
19 consistent gets
3 physical reads
0 redo size
327 bytes sent via SQL*Net to client
481 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SQL的处理阶段:
SQL 的处理阶段会包括:解析、优化、产生行源和执行。当然并不是所有Oracle数据库都会这些处理,这得结合具体的SQL语句。
SQL的第一阶段:解析
这一阶段会将SQL语句的各个片段,分离到由其他进程处理的数据结构,当Oracle数据库得到应用程序的指示下,就会对下一个语句进行解析,这就意味着减少解析数目的不是Oracle数据库本身,而是应用程序。
当应用程序发出SQL语句时,该应用程序就会向数据库发出一个解析调用,用来准备执行该语句。解析调用会打开或者创建一个游标,其中包含了已分析的SQL语句的处理信息。在解析调用时,Oracle数据库会执行以下检查:
- 语法检查 :主要是检查SQL语句的语法是否符合标准格式
- 语义检查 : 语义检查是确定该语句中的对象是否存在
- 共享池检查 :用于确定是否可以跳过占用大量资源的语句处理过程
如果前面的检查有错,那么在SQL语句执行之前是不会执行的。当然,并不是所有错误都能在解析过程中所检查到,例如:锁
两个概念:硬解析和软解析
1)硬解析
如果当前数据库中没有执行过的语句,那么就会生成一个执行代码。这个操作就叫硬解析或者库缓存未命中。
在硬解析期间,数据库会多次访问库缓存和数据字典缓存。当数据库访问到这些区域时,就会给她们上了个锁,以防止它们的定义不会被修改,当然这个代价就是会增加语句的执行时间,降低并发性。
2)软解析
如果提交的SQL语句在共享池里语句相同,那么就会利用存在的语句代码,这个过程就叫做软解析或者库缓存命中。
一般情况,软解析比硬解析所要达到的效果会很好,因为数据库可以跳过优化和行源生成的步骤,直接进入到这执行过程。
两个概念:硬解析和软解析
1)硬解析
如果当前数据库中没有执行过的语句,那么就会生成一个执行代码。这个操作就叫硬解析或者库缓存未命中。
在硬解析期间,数据库会多次访问库缓存和数据字典缓存。当数据库访问到这些区域时,就会给她们上了个锁,以防止它们的定义不会被修改,当然这个代价就是会增加语句的执行时间,降低并发性。
2)软解析
如果提交的SQL语句在共享池里语句相同,那么就会利用存在的语句代码,这个过程就叫做软解析或者库缓存命中。
一般情况,软解析比硬解析所要达到的效果会很好,因为数据库可以跳过优化和行源生成的步骤,直接进入到这执行过程。
SQL执行第二阶段:优化
实际上Oracle数据库对查询的优化,是在统计收集数据的执行信息,这些信息来包括使用行数,数据集大小等,利用这些信息来生产各种可能的执行计划,并为每个计划分配一个成本值,这时候Oracle数据库就会具有最低成本的技术(CBO)
PS:提个问题 为什么DDL永远不会被优化,而DML语句必须执行一次硬解析?
SQL执行的第三阶段:行源生成
行源生成是数据库的一个软件产生的计划过程,它从优化器收集到已经优化的执行计划,并生成一个查询计划的迭代计划,用于生成结果集。行源生成会生成一个行源树,他是一个行源的集合,是执行计划中的某一步骤返回的行集结果
例如:
SELECT /*+gather_plan_statistics test12*/ T.METER_ID "[dianneng]" FROM MPAC.D_METER T LEFT JOIN (SELECT M.EQUIP_ID,
M.CONC_CODE, ROW_NUMBER() OVER(PARTITION BY EQUIP_ID ORDER BY DETECT_DATE DESC) RN FROM (SELECT
T1.EQUIP_ID,T1.CONC_CODE,T1.DETECT_DATE FROM MPAC.T_DETECT_MET_RSLT T1 UNION ALL SELECT
T2.EQUIP_ID,T2.CONC_CODE,T2.DETECT_DATE FROM MPAC.T_SAMPLING_MET_RSLT T2 UNION ALL SELECT
T3.EQUIP_ID,T3.CONC_CODE,T3.DETECT_DATE FROM MPAC.T_COMPARE_MET_RSLT T3) M) TR ON T.METER_ID = TR.EQUIP_ID AND TR.RN=1
WHERE T.STATUS_CODE = '017' AND T.SORT_CODE='10' AND (TR.CONC_CODE='02' OR TR.CONC_CODE IS NULL) AND T.PR_CODE='1'
Execution Plan
----------------------------------------------------------
Plan hash value: 1888591727
--------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1687 | 74228 | | 23874 (1)| 00:04:47 | | |
|* 1 | HASH JOIN OUTER | | 1687 | 74228 | | 23874 (1)| 00:04:47 | | |
|* 2 | TABLE ACCESS BY GLOBAL INDEX ROWID | D_METER | 1687 | 30366 | | 240 (1)| 00:00:03 | ROWID | ROWID |
|* 3 | INDEX RANGE SCAN | IDX_D_METER06048 | 4358 | | | 8 (0)| 00:00:01 | | |
|* 4 | VIEW | | 572K| 14M| | 23627 (1)| 00:04:44 | | |
|* 5 | WINDOW SORT PUSHED RANK | | 572K| 12M| 17M| 23627 (1)| 00:04:44 | | |
| 6 | VIEW | | 572K| 12M| | 19774 (1)| 00:03:58 | | |
| 7 | UNION-ALL | | | | | | | | |
| 8 | TABLE ACCESS BY GLOBAL INDEX ROWID| T_DETECT_MET_RSLT | 570K| 10M| | 16851 (1)| 00:03:23 | ROWID | ROWID |
|* 9 | INDEX RANGE SCAN | IDX_T_DETECT_MET_RSLT_04 | 570K| | | 1040 (1)| 00:00:13 | | |
|* 10 | TABLE ACCESS FULL | T_SAMPLING_MET_RSLT | 2052 | 43092 | | 2903 (1)| 00:00:35 | | |
|* 11 | TABLE ACCESS FULL | T_COMPARE_MET_RSLT | 387 | 7353 | | 19 (0)| 00:00:01 | | |
--------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T"."METER_ID"="TR"."EQUIP_ID"(+))
2 - filter("T"."SORT_CODE"='10' AND "T"."PR_CODE"='1')
3 - access("T"."STATUS_CODE"='017')
4 - filter("TR"."RN"(+)=1)
5 - filter(ROW_NUMBER() OVER ( PARTITION BY "EQUIP_ID" ORDER BY INTERNAL_FUNCTION("DETECT_DATE") DESC )<=1)
9 - access("CONC_CODE"='02')
10 - filter("CONC_CODE"='02')
11 - filter("CONC_CODE"='02')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
19 consistent gets
3 physical reads
0 redo size
327 bytes sent via SQL*Net to client
481 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30430420/viewspace-1795904/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/30430420/viewspace-1795904/
21

被折叠的 条评论
为什么被折叠?



