- 浏览: 93052 次
- 性别:
- 来自: 上海
-
文章分类
最新评论
如何看懂ORACLE执行计划
一、什么是执行计划
An explain plan is a representation of the access path that is taken when a query is executed within Oracle.
二、如何访问数据
At the physical level Oracle reads blocks of data. The smallest amount of data read is a single Oracle block, the largest is constrained by operating system limits (and multiblock i/o). Logically Oracle finds the data to read by using the following methods:
Full Table Scan (FTS) --全表扫描
Index Lookup (unique & non-unique) --索引扫描(唯一和非唯一)
Rowid --物理行id
三、执行计划层次关系
When looking at a plan, the rightmost (ie most inndented) uppermost operation is the first thing that is executed. --采用最右最上最先执行的原则看层次关系,在同一级如果某个动作没有子ID就最先执行
1.一个简单的例子:
SQL> select /*+parallel (e 4)*/ * from emp e;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=82 Bytes=7134)
1 0 TABLE ACCESS* (FULL) OF 'EMP' (Cost=1 Card=82 Bytes=7134):Q5000
--[:Q5000]表示是并行方式
1 PARALLEL_TO_SERIAL SELECT /*+ NO_EXPAND ROWID(A1) */ A1."EMPNO"
,A1."ENAME",A1."JOB",A1."MGR",A1."HI
优化模式是CHOOSE的情况下,看Cost参数是否有值来决定采用CBO还是RBO:
SELECT STATEMENT [CHOOSE] Cost=1234 --Cost有值,采用CBO
SELECT STATEMENT [CHOOSE] --Cost为空,采用RBO(9I是如此显示的)
2.层次的父子关系的例子:
PARENT1
**FIRST CHILD
****FIRST GRANDCHILD
**SECOND CHILD
Here the same principles apply, the FIRST GRANDCHILD is the initial operation then the FIRST CHILD followed by the SECOND CHILD and finally the PARENT collates the output.
四、例子解说
Execution Plan
----------------------------------------------------------
0 **SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=8 Bytes=248)
1 0 **HASH JOIN (Cost=3 Card=8 Bytes=248)
2 1 ****TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=3 Bytes=36)
3 1 ****TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=16 Bytes=304)
左侧的两排数据,前面的是序列号ID,后面的是对应的PID(父ID)。
A shortened summary of this is:
Execution starts with ID=0: SELECT STATEMENT but this is dependand on it's child objects
So it executes its first child step: ID=1 PID=0 HASH JOIN but this is dependand on it's child objects
So it executes its first child step: ID=2 PID=1 TABLE ACCESS (FULL) OF 'DEPT'
Then the second child step: ID=3 PID=2 TABLE ACCESS (FULL) OF 'EMP'
Rows are returned to the parent step(s) until finished
五、表访问方式
1.Full Table Scan (FTS) 全表扫描
In a FTS operation, the whole table is read up to the high water mark (HWM). The HWM marks the last block in the table that has ever had data written to it. If you have deleted all the rows then you will still read up to the HWM. Truncate resets the HWM back to the start of the table. FTS uses multiblock i/o to read the blocks from disk. --全表扫描模式下会读数据到表的高水位线(HWM即表示表曾经扩展的最后一个数据块),读取速度依赖于Oracle初始化参数db_block_multiblock_read_count(我觉得应该这样翻译:FTS扫描会使表使用上升到高水位(HWM),HWM标识了表最后写入数据的块,如果你用DELETE删除了所有的数据表仍然处于高水位(HWM),只有用TRUNCATE才能使表回归,FTS使用多IO从磁盘读取数据块).
Query Plan
------------------------------------
SELECT STATEMENT [CHOOSE] Cost=1
**INDEX UNIQUE SCAN EMP_I1 --如果索引里就找到了所要的数据,就不会再去访问表
2.Index Lookup 索引扫描
There are 5 methods of index lookup:
index unique scan --索引唯一扫描
Method for looking up a single key value via a unique index. always returns a single value, You must supply AT LEAST the leading column of the index to access data via the index.
eg:SQL> explain plan for select empno,ename from emp where empno=10;
index range scan --索引局部扫描
Index range scan is a method for accessing a range values of a particular column. AT LEAST the leading column of the index must be supplied to access data via the index. Can be used for range operations (e.g. > < <> >= <= between) .
eg:SQL> explain plan for select mgr from emp where mgr = 5;
index full scan --索引全局扫描
Full index scans are only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort. For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order.
eg: SQL> explain plan for select empno,ename from big_emp order by empno,ename;
index fast full scan --索引快速全局扫描,不带order by情况下常发生
Scans all the block in the index, Rows are not returned in sorted order, Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO, may be hinted using INDEX_FFS hint, uses multiblock i/o, can be executed in parallel, can be used to access second column of concatenated indexes. This is because we are selecting all of the index.
eg: SQL> explain plan for select empno,ename from big_emp;
index skip scan --索引跳跃扫描,where条件列是非索引的前导列情况下常发生
Index skip scan finds rows even if the column is not the leading column of a concatenated index. It skips the first column(s) during the search.
eg:SQL> create index i_emp on emp(empno, ename);
SQL> select /*+ index_ss(emp i_emp)*/ job from emp where ename='SMITH';
3.Rowid 物理ID扫描
This is the quickest access method available.Oracle retrieves the specified block and extracts the rows it is interested in. --Rowid扫描是最快的访问数据方式
六、表连接方式
七、运算符
1.sort --排序,很消耗资源
There are a number of different operations that promote sorts:
(1)order by clauses (2)group by (3)sort merge join –-这三个会产生排序运算
2.filter --过滤,如not in、min函数等容易产生
Has a number of different meanings, used to indicate partition elimination, may also indicate an actual filter step where one row source is filtering, another, functions such as min may introduce filter steps into query plans.
3.view --视图,大都由内联视图产生(可能深入到视图基表)
When a view cannot be merged into the main query you will often see a projection view operation. This indicates that the 'view' will be selected from directly as opposed to being broken down into joins on the base tables. A number of constructs make a view non mergeable. Inline views are also non mergeable.
eg: SQL> explain plan for
select ename,tot from emp,(select empno,sum(empno) tot from big_emp group by empno) tmp
where emp.empno = tmp.empno;
Query Plan
------------------------
SELECT STATEMENT [CHOOSE]
**HASH JOIN
**TABLE ACCESS FULL EMP [ANALYZED]
**VIEW
****SORT GROUP BY
******INDEX FULL SCAN BE_IX
4.partition view --分区视图
Partition views are a legacy technology that were superceded by the partitioning option. This section of the article is provided as reference for such legacy systems.
示例:假定A、B、C都是不是小表,且在A表上一个组合索引:A(a.col1,a.col2) ,注意a.col1列为索引的引导列。考虑下面的查询:
select A.col4 from A , B , C
where B.col3 = 10 and A.col1 = B.col1 and A.col2 = C.col2 and C.col3 = 5;
Execution Plan
------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 SORT (JOIN)
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'B'
5 3 TABLE ACCESS (BY INDEX ROWID) OF 'A'
6 5 INDEX (RANGE SCAN) OF 'INX_COL12A' (NON-UNIQUE)
7 1 SORT (JOIN)
8 7 TABLE ACCESS (FULL) OF 'C'
Statistics(统计信息参数,参见另外个转载的文章)
--------------------------------------
0 recursive calls(归调用次数)
8 db block gets(从磁盘上读取的块数,即通过update/delete/select for update读的次数)
6 consistent gets(从内存里读取的块数,即通过不带for update的select 读的次数)
0 physical reads(物理读—从磁盘读到数据块数量,一般来说是'consistent gets' + 'db block gets')
0 redo size (重做数——执行SQL的过程中,产生的重做日志的大小)
551 bytes sent via SQL*Net to client
430 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory) (在内存中发生的排序)
0 sorts (disk) (在硬盘中发生的排序)
6 rows processed
在表做连接时,只能2个表先做连接,然后将连接后的结果作为一个row source,与剩下的表做连接,在上面的例子中,连接顺序为B与A先连接,然后再与C连接:
B <---> A <---> C
col3=10 col3=5
如果没有执行计划,分析一下,上面的3个表应该拿哪一个作为第一个驱动表?从SQL语句看来,只有B表与C表上有限制条件,所以第一个驱动表应该为这2个表中的一个,到底是哪一个呢?
B表有谓词B.col3 = 10,这样在对B表做全表扫描的时候就将where子句中的限制条件(B.col3 = 10)用上,从而得到一个较小的row source, 所以B表应该作为第一个驱动表。而且这样的话,如果再与A表做关联,可以有效利用A表的索引(因为A表的col1列为leading column)。
上面的查询中C表上也有谓词(C.col3 = 5),有人可能认为C表作为第一个驱动表也能获得较好的性能。让我们再来分析一下:如果C表作为第一个驱动表,则能保证驱动表生成很小的row source,但是看看连接条件A.col2 = C.col2,此时就没有机会利用A表的索引,因为A表的col2列不为leading column,这样nested loop的效率很差,从而导致查询的效率很差。所以对于NL连接选择正确的驱动表很重要。
因此上面查询比较好的连接顺序为(B - - > A) - - > C。如果数据库是基于代价的优化器,它会利用计算出的代价来决定合适的驱动表与合适的连接顺序。一般来说,CBO都会选择正确的连接顺序,如果CBO选择了比较差的连接顺序,我们还可以使用ORACLE提供的hints来让CBO采用正确的连接顺序。如下所示
select /*+ ordered */ A.col4
from B,A,C
where B.col3 = 10 and A.col1 = B.col1 and A.col2 = C.col2 and C.col3 = 5
既然选择正确的驱动表这么重要,那么让我们来看一下执行计划,到底各个表之间是如何关联的,从而得到执行计划中哪个表应该为驱动表:
在执行计划中,需要知道哪个操作是先执行的,哪个操作是后执行的,这对于判断哪个表为驱动表有用处。判断之前,如果对表的访问是通过rowid,且该rowid的值是从索引扫描中得来得,则将该索引扫描先从执行计划中暂时去掉。然后在执行计划剩下的部分中,判断执行顺序的指导原则就是:最右、最上的操作先执行。具体解释如下:
得到去除妨碍判断的索引扫描后的执行计划:Execution Plan
-------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 SORT (JOIN)
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'B'
5 3 TABLE ACCESS (BY INDEX ROWID) OF 'A'
6 5 INDEX (RANGE SCAN) OF 'INX_COL12A' (NON-UNIQUE)
7 1 SORT (JOIN)
8 7 TABLE ACCESS (FULL) OF 'C'
看执行计划的第3列,即字母部分,每列值的左面有空格作为缩进字符。在该列值左边的空格越多,说明该列值的缩进越多,该列值也越靠右。如上面的执行计划所示:第一列值为6的行的缩进最多,即该行最靠右;第一列值为4、5的行的缩进一样,其靠右的程度也一样,但是第一列值为4的行比第一列值为5的行靠上;谈论上下关系时,只对连续的、缩进一致的行有效。
从这个图中我们可以看到,对于NESTED LOOPS部分,最右、最上的操作是TABLE ACCESS (FULL) OF 'B',所以这一操作先执行,所以该操作对应的B表为第一个驱动表(外部表),自然,A表就为内部表了。从图中还可以看出,B与A表做嵌套循环后生成了新的row source ,对该row source进行来排序后,与C表对应的排序了的row source(应用了C.col3 = 5限制条件)进行SMJ连接操作。所以从上面可以得出如下事实:B表先与A表做嵌套循环,然后将生成的row source与C表做排序—合并连接。
通过分析上面的执行计划,我们不能说C表一定在B、A表之后才被读取,事实上,B表有可能与C表同时被读入内存,因为将表中的数据读入内存的操作可能为并行的。事实上许多操作可能为交叉进行的,因为ORACLE读取数据时,如果就是需要一行数据也是将该行所在的整个数据块读入内存,而且有可能为多块读。
看执行计划时,我们的关键不是看哪个操作先执行,哪个操作后执行,而是关键看表之间连接的顺序(如得知哪个为驱动表,这需要从操作的顺序进行判断)、使用了何种类型的关联及具体的存取路径(如判断是否利用了索引)
在从执行计划中判断出哪个表为驱动表后,根据我们的知识判断该表作为驱动表(就像上面判断ABC表那样)是否合适,如果不合适,对SQL语句进行更改,使优化器可以选择正确的驱动表。
一、什么是执行计划
An explain plan is a representation of the access path that is taken when a query is executed within Oracle.
二、如何访问数据
At the physical level Oracle reads blocks of data. The smallest amount of data read is a single Oracle block, the largest is constrained by operating system limits (and multiblock i/o). Logically Oracle finds the data to read by using the following methods:
Full Table Scan (FTS) --全表扫描
Index Lookup (unique & non-unique) --索引扫描(唯一和非唯一)
Rowid --物理行id
三、执行计划层次关系
When looking at a plan, the rightmost (ie most inndented) uppermost operation is the first thing that is executed. --采用最右最上最先执行的原则看层次关系,在同一级如果某个动作没有子ID就最先执行
1.一个简单的例子:
SQL> select /*+parallel (e 4)*/ * from emp e;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=82 Bytes=7134)
1 0 TABLE ACCESS* (FULL) OF 'EMP' (Cost=1 Card=82 Bytes=7134):Q5000
--[:Q5000]表示是并行方式
1 PARALLEL_TO_SERIAL SELECT /*+ NO_EXPAND ROWID(A1) */ A1."EMPNO"
,A1."ENAME",A1."JOB",A1."MGR",A1."HI
优化模式是CHOOSE的情况下,看Cost参数是否有值来决定采用CBO还是RBO:
SELECT STATEMENT [CHOOSE] Cost=1234 --Cost有值,采用CBO
SELECT STATEMENT [CHOOSE] --Cost为空,采用RBO(9I是如此显示的)
2.层次的父子关系的例子:
PARENT1
**FIRST CHILD
****FIRST GRANDCHILD
**SECOND CHILD
Here the same principles apply, the FIRST GRANDCHILD is the initial operation then the FIRST CHILD followed by the SECOND CHILD and finally the PARENT collates the output.
四、例子解说
Execution Plan
----------------------------------------------------------
0 **SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=8 Bytes=248)
1 0 **HASH JOIN (Cost=3 Card=8 Bytes=248)
2 1 ****TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=3 Bytes=36)
3 1 ****TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=16 Bytes=304)
左侧的两排数据,前面的是序列号ID,后面的是对应的PID(父ID)。
A shortened summary of this is:
Execution starts with ID=0: SELECT STATEMENT but this is dependand on it's child objects
So it executes its first child step: ID=1 PID=0 HASH JOIN but this is dependand on it's child objects
So it executes its first child step: ID=2 PID=1 TABLE ACCESS (FULL) OF 'DEPT'
Then the second child step: ID=3 PID=2 TABLE ACCESS (FULL) OF 'EMP'
Rows are returned to the parent step(s) until finished
五、表访问方式
1.Full Table Scan (FTS) 全表扫描
In a FTS operation, the whole table is read up to the high water mark (HWM). The HWM marks the last block in the table that has ever had data written to it. If you have deleted all the rows then you will still read up to the HWM. Truncate resets the HWM back to the start of the table. FTS uses multiblock i/o to read the blocks from disk. --全表扫描模式下会读数据到表的高水位线(HWM即表示表曾经扩展的最后一个数据块),读取速度依赖于Oracle初始化参数db_block_multiblock_read_count(我觉得应该这样翻译:FTS扫描会使表使用上升到高水位(HWM),HWM标识了表最后写入数据的块,如果你用DELETE删除了所有的数据表仍然处于高水位(HWM),只有用TRUNCATE才能使表回归,FTS使用多IO从磁盘读取数据块).
Query Plan
------------------------------------
SELECT STATEMENT [CHOOSE] Cost=1
**INDEX UNIQUE SCAN EMP_I1 --如果索引里就找到了所要的数据,就不会再去访问表
2.Index Lookup 索引扫描
There are 5 methods of index lookup:
index unique scan --索引唯一扫描
Method for looking up a single key value via a unique index. always returns a single value, You must supply AT LEAST the leading column of the index to access data via the index.
eg:SQL> explain plan for select empno,ename from emp where empno=10;
index range scan --索引局部扫描
Index range scan is a method for accessing a range values of a particular column. AT LEAST the leading column of the index must be supplied to access data via the index. Can be used for range operations (e.g. > < <> >= <= between) .
eg:SQL> explain plan for select mgr from emp where mgr = 5;
index full scan --索引全局扫描
Full index scans are only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort. For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order.
eg: SQL> explain plan for select empno,ename from big_emp order by empno,ename;
index fast full scan --索引快速全局扫描,不带order by情况下常发生
Scans all the block in the index, Rows are not returned in sorted order, Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO, may be hinted using INDEX_FFS hint, uses multiblock i/o, can be executed in parallel, can be used to access second column of concatenated indexes. This is because we are selecting all of the index.
eg: SQL> explain plan for select empno,ename from big_emp;
index skip scan --索引跳跃扫描,where条件列是非索引的前导列情况下常发生
Index skip scan finds rows even if the column is not the leading column of a concatenated index. It skips the first column(s) during the search.
eg:SQL> create index i_emp on emp(empno, ename);
SQL> select /*+ index_ss(emp i_emp)*/ job from emp where ename='SMITH';
3.Rowid 物理ID扫描
This is the quickest access method available.Oracle retrieves the specified block and extracts the rows it is interested in. --Rowid扫描是最快的访问数据方式
六、表连接方式
七、运算符
1.sort --排序,很消耗资源
There are a number of different operations that promote sorts:
(1)order by clauses (2)group by (3)sort merge join –-这三个会产生排序运算
2.filter --过滤,如not in、min函数等容易产生
Has a number of different meanings, used to indicate partition elimination, may also indicate an actual filter step where one row source is filtering, another, functions such as min may introduce filter steps into query plans.
3.view --视图,大都由内联视图产生(可能深入到视图基表)
When a view cannot be merged into the main query you will often see a projection view operation. This indicates that the 'view' will be selected from directly as opposed to being broken down into joins on the base tables. A number of constructs make a view non mergeable. Inline views are also non mergeable.
eg: SQL> explain plan for
select ename,tot from emp,(select empno,sum(empno) tot from big_emp group by empno) tmp
where emp.empno = tmp.empno;
Query Plan
------------------------
SELECT STATEMENT [CHOOSE]
**HASH JOIN
**TABLE ACCESS FULL EMP [ANALYZED]
**VIEW
****SORT GROUP BY
******INDEX FULL SCAN BE_IX
4.partition view --分区视图
Partition views are a legacy technology that were superceded by the partitioning option. This section of the article is provided as reference for such legacy systems.
示例:假定A、B、C都是不是小表,且在A表上一个组合索引:A(a.col1,a.col2) ,注意a.col1列为索引的引导列。考虑下面的查询:
select A.col4 from A , B , C
where B.col3 = 10 and A.col1 = B.col1 and A.col2 = C.col2 and C.col3 = 5;
Execution Plan
------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 SORT (JOIN)
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'B'
5 3 TABLE ACCESS (BY INDEX ROWID) OF 'A'
6 5 INDEX (RANGE SCAN) OF 'INX_COL12A' (NON-UNIQUE)
7 1 SORT (JOIN)
8 7 TABLE ACCESS (FULL) OF 'C'
Statistics(统计信息参数,参见另外个转载的文章)
--------------------------------------
0 recursive calls(归调用次数)
8 db block gets(从磁盘上读取的块数,即通过update/delete/select for update读的次数)
6 consistent gets(从内存里读取的块数,即通过不带for update的select 读的次数)
0 physical reads(物理读—从磁盘读到数据块数量,一般来说是'consistent gets' + 'db block gets')
0 redo size (重做数——执行SQL的过程中,产生的重做日志的大小)
551 bytes sent via SQL*Net to client
430 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory) (在内存中发生的排序)
0 sorts (disk) (在硬盘中发生的排序)
6 rows processed
在表做连接时,只能2个表先做连接,然后将连接后的结果作为一个row source,与剩下的表做连接,在上面的例子中,连接顺序为B与A先连接,然后再与C连接:
B <---> A <---> C
col3=10 col3=5
如果没有执行计划,分析一下,上面的3个表应该拿哪一个作为第一个驱动表?从SQL语句看来,只有B表与C表上有限制条件,所以第一个驱动表应该为这2个表中的一个,到底是哪一个呢?
B表有谓词B.col3 = 10,这样在对B表做全表扫描的时候就将where子句中的限制条件(B.col3 = 10)用上,从而得到一个较小的row source, 所以B表应该作为第一个驱动表。而且这样的话,如果再与A表做关联,可以有效利用A表的索引(因为A表的col1列为leading column)。
上面的查询中C表上也有谓词(C.col3 = 5),有人可能认为C表作为第一个驱动表也能获得较好的性能。让我们再来分析一下:如果C表作为第一个驱动表,则能保证驱动表生成很小的row source,但是看看连接条件A.col2 = C.col2,此时就没有机会利用A表的索引,因为A表的col2列不为leading column,这样nested loop的效率很差,从而导致查询的效率很差。所以对于NL连接选择正确的驱动表很重要。
因此上面查询比较好的连接顺序为(B - - > A) - - > C。如果数据库是基于代价的优化器,它会利用计算出的代价来决定合适的驱动表与合适的连接顺序。一般来说,CBO都会选择正确的连接顺序,如果CBO选择了比较差的连接顺序,我们还可以使用ORACLE提供的hints来让CBO采用正确的连接顺序。如下所示
select /*+ ordered */ A.col4
from B,A,C
where B.col3 = 10 and A.col1 = B.col1 and A.col2 = C.col2 and C.col3 = 5
既然选择正确的驱动表这么重要,那么让我们来看一下执行计划,到底各个表之间是如何关联的,从而得到执行计划中哪个表应该为驱动表:
在执行计划中,需要知道哪个操作是先执行的,哪个操作是后执行的,这对于判断哪个表为驱动表有用处。判断之前,如果对表的访问是通过rowid,且该rowid的值是从索引扫描中得来得,则将该索引扫描先从执行计划中暂时去掉。然后在执行计划剩下的部分中,判断执行顺序的指导原则就是:最右、最上的操作先执行。具体解释如下:
得到去除妨碍判断的索引扫描后的执行计划:Execution Plan
-------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
2 1 SORT (JOIN)
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'B'
5 3 TABLE ACCESS (BY INDEX ROWID) OF 'A'
6 5 INDEX (RANGE SCAN) OF 'INX_COL12A' (NON-UNIQUE)
7 1 SORT (JOIN)
8 7 TABLE ACCESS (FULL) OF 'C'
看执行计划的第3列,即字母部分,每列值的左面有空格作为缩进字符。在该列值左边的空格越多,说明该列值的缩进越多,该列值也越靠右。如上面的执行计划所示:第一列值为6的行的缩进最多,即该行最靠右;第一列值为4、5的行的缩进一样,其靠右的程度也一样,但是第一列值为4的行比第一列值为5的行靠上;谈论上下关系时,只对连续的、缩进一致的行有效。
从这个图中我们可以看到,对于NESTED LOOPS部分,最右、最上的操作是TABLE ACCESS (FULL) OF 'B',所以这一操作先执行,所以该操作对应的B表为第一个驱动表(外部表),自然,A表就为内部表了。从图中还可以看出,B与A表做嵌套循环后生成了新的row source ,对该row source进行来排序后,与C表对应的排序了的row source(应用了C.col3 = 5限制条件)进行SMJ连接操作。所以从上面可以得出如下事实:B表先与A表做嵌套循环,然后将生成的row source与C表做排序—合并连接。
通过分析上面的执行计划,我们不能说C表一定在B、A表之后才被读取,事实上,B表有可能与C表同时被读入内存,因为将表中的数据读入内存的操作可能为并行的。事实上许多操作可能为交叉进行的,因为ORACLE读取数据时,如果就是需要一行数据也是将该行所在的整个数据块读入内存,而且有可能为多块读。
看执行计划时,我们的关键不是看哪个操作先执行,哪个操作后执行,而是关键看表之间连接的顺序(如得知哪个为驱动表,这需要从操作的顺序进行判断)、使用了何种类型的关联及具体的存取路径(如判断是否利用了索引)
在从执行计划中判断出哪个表为驱动表后,根据我们的知识判断该表作为驱动表(就像上面判断ABC表那样)是否合适,如果不合适,对SQL语句进行更改,使优化器可以选择正确的驱动表。
发表评论
-
转载 NoSQL非关系型数据库学习 这样对比下HBase, Memcached, MongoDB, Redis和Solr
2014-11-14 16:27 0Name HBase Memc ... -
Oracle创建dblink报错:ORA-01017、ORA-02063解决 (转载)
2013-07-23 17:09 1585Oracle创建dblink报错:ORA-01017、ORA ... -
ORACLE查看并修改最大连接数
2012-11-15 17:09 0阅读:1157次 时间:2010-03-15 2 ... -
oracle apache服务占用80端口
2012-06-19 09:27 780Posted on 2008-04-28 13:17 alle ... -
DataStage 简介 (
2012-05-18 14:01 1130DataStage 简介 (2010-05-27 19 ... -
oracle常用命令
2012-05-09 13:38 01.增加主键 alter table TABLE_NAM ... -
esri 常见几何对象的构造
2012-05-03 16:24 895常见几何对象的构造 介绍ESRI的ST_GEOMETRY的几 ... -
GIS 中地理坐标和屏幕坐标的标准转换方法
2012-05-03 16:10 1454GIS 中地理坐标和屏幕坐标的标准转换方法 在GIS中,当你 ... -
Oracle Spatial的简单应用补充——shapefile导入ORACLE
2012-05-03 15:32 1046Oracle Spatial的简单应用补充——shapefil ... -
weblgic 中oracle rac的配置
2012-05-02 18:55 0通过 select * from gv$instance;来查 ... -
Oracle 10g RAC的负载均衡配置
2012-04-27 12:32 0Oracle 10g RAC的负载均衡配置 负载均衡是指连接 ... -
weblogic集群配置
2012-04-26 11:00 0weblogic集群配置 -
数据库名,数据库实例名SID,数据库服务名,全局数据库名
2012-04-26 10:20 926数据库名,数据库实例名SID,数据库服务名,全局数据库名 一、 ... -
weblogic启动与关闭的自动登陆总结
2012-04-25 19:58 1020weblogic启动与关闭的自 ... -
weblogic 10 linux
2012-04-23 23:59 1074[日期:2010-06-13] 来源:Linux社区 作者: ... -
OJDBC版本区别 [ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别]
2012-03-07 11:01 1110OJDBC版本区别 [ojdbc14.jar,ojdbc5.j ... -
oracle Spatial 函数
2011-12-22 15:25 2240Oracle_spatial的函数 一sdo_Geom包的函数 ... -
oracel表类型
2011-10-26 15:19 0表类型: 1堆组织表(heap organized table ... -
oracle table函数
2011-08-24 16:56 2068PL/SQL表---table()函数用法 /* PL/SQ ... -
oracel 不走索引的原因(来自网络)
2011-08-18 10:54 1376SQL优化器简介 基于规 ...
相关推荐
内容概要:本文详细介绍了基于DSP28035的CAN在线升级程序及其Bootloader开发服务。主要内容涵盖CAN通讯协议的设计与实现,包括CAN模块初始化、Hex文件解析、内存分配以及应用程序跳转等关键技术点。此外,还讨论了上位机软件的开发选择和技术难点,如超时检测、CRC校验、中断向量表重映射等。文中不仅提供了具体的代码示例,还分享了许多实践经验,如避免内存越界、处理地址扩展等问题的方法。 适合人群:从事嵌入式系统开发的技术人员,尤其是那些对DSP28035感兴趣或正在使用该处理器进行项目的开发者。 使用场景及目标:适用于需要实现远程固件更新的嵌入式设备制造商,旨在提高产品维护效率并减少物理干预的需求。通过学习本文,读者可以掌握如何构建一个稳定可靠的CAN在线升级解决方案。 其他说明:文章强调了协议设计的重要性,并指出了一些常见的错误和陷阱,帮助读者避开这些问题。同时,作者还提到了一些优化技巧,比如利用DMA加速数据传输、合理规划内存布局等,以确保系统的高性能和稳定性。
内容概要:本文详细介绍了基于UDS(Unified Diagnostic Services)协议的Bootloader在Autosar架构下的定制开发过程。主要内容涵盖Autosar架构与DCM(诊断通信管理)模块的集成,以及针对不同系列芯片(如NXP S32K、Infineon TC275等)的具体实现细节。文中通过具体的代码示例展示了从初始化、诊断服务处理到跳转应用程序的全过程,并讨论了不同芯片之间的差异及其应对策略。此外,还涉及了存储器管理、数据传输优化和安全启动等方面的内容。 适合人群:从事汽车电子开发的专业人士,尤其是对Bootloader开发感兴趣的工程师和技术人员。 使用场景及目标:适用于需要深入了解和实现基于UDS协议的Bootloader定制项目的团队。主要目标是提高汽车电子系统的诊断效率和可靠性,同时确保不同芯片平台间的兼容性和性能最优化。 其他说明:文章不仅提供了理论指导,还包括大量实用的代码片段和实践经验分享,帮助读者更好地理解和应用于实际项目中。
内容概要:本文详细介绍了如何通过Modbus协议实现昆仑通态触摸屏与台达VFD-M系列变频器之间的通讯,具体涵盖了硬件接线、关键参数设置、MCGS组态环境中的设备配置、变量定义、界面设计及脚本编写等内容。文中不仅提供了详细的参数设置方法,还分享了一些常见的调试技巧和故障排查方法,如硬件接线注意事项、参数设置要点、通讯故障解决措施等。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是那些需要进行触摸屏与变频器通讯集成工作的人员。 使用场景及目标:适用于需要通过触摸屏远程控制变频器的应用场景,如工厂自动化生产线、机械设备控制等。目标是让读者能够独立完成从硬件连接到软件编程的整个通讯系统搭建过程。 其他说明:文章强调了实际操作中的注意事项和容易忽视的细节,如硬件接线的特殊性、参数设置的准确性、通讯协议的具体应用等,有助于提高项目的成功率和稳定性。同时,提供了丰富的调试工具和方法,帮助读者快速定位和解决问题。
内容概要:本文详细介绍了一种750W高功率因数(PF)充电机电源方案,采用UCC28070、ST6599和PIC16F193X三款芯片组合。UCC28070用于功率因数校正(PFC),通过交错式升压电路提升PF值;ST6599负责LLC谐振变换器,确保高效功率转换;PIC16F193X作为微控制器进行智能控制。文中不仅提供了详细的原理图、设计文件和烧录程序,还分享了具体的应用代码和调试技巧。此外,引用了华南理工大学硕士学位论文,深入探讨了设计优化方法。 适合人群:电源设计工程师、电子工程专业学生、对高效电源设计感兴趣的开发者。 使用场景及目标:适用于需要高功率因数和高效能的充电机应用场景,如电动汽车充电桩、数据中心备用电源等。目标是帮助读者掌握高效电源设计的技术细节,提升产品性能。 其他说明:本文不仅提供了硬件设计思路,还包括软件编程实例,如PFC控制算法、LLC频率调整、故障保护机制等。同时强调了实际应用中的注意事项,如寄存器配置、元件选型、PCB布局等。
内容概要:本文详细介绍了基于200smart PLC和昆仑通态触摸屏构建的一拖三恒压供水系统的实现方法及其调试经验。主要内容涵盖系统架构设计、PID控制参数整定、触摸屏配置、水泵轮换逻辑以及常见的调试技巧和注意事项。文中强调了PID控制在变频器调度中的重要性,提供了具体的代码示例和技术细节,如PID输出限幅处理、Modbus通信映射、压力反馈处理等。此外,作者还分享了许多宝贵的实战经验和教训,如避免在触摸屏上进行复杂运算、确保硬件布局合理性等。 适合人群:从事自动化控制系统设计与调试的技术人员,尤其是对PID控制和PLC编程有一定基础的研发人员。 使用场景及目标:适用于需要精确控制供水压力的工业场合,如小区二次供水、厂房循环水系统等。目标是帮助技术人员理解和掌握一拖三恒压供水系统的实现方法,提高系统的稳定性和可靠性。 其他说明:文中提到的具体参数和代码片段可供参考,但在实际应用中需根据具体情况进行适当调整。
该资源为natsort-3.1.2.tar.gz,欢迎下载使用哦!
该资源为natsort-2.0.0-py2.7.egg,欢迎下载使用哦!
内容概要:本文详细阐述了DeepSeek大模型在服装行业的应用方案,旨在通过人工智能技术提升服装企业的运营效率和市场竞争力。文章首先介绍了服装行业的现状与挑战,指出传统模式难以应对复杂的市场变化。DeepSeek大模型凭借其强大的数据分析和模式识别能力,能够精准预测市场趋势、优化供应链管理、提升产品设计效率,并实现个性化推荐。具体应用场景包括设计灵感生成、自动化设计、虚拟试衣、需求预测、生产流程优化、精准营销、智能客服、用户体验提升等。此外,文章还探讨了数据安全与隐私保护的重要性,以及技术实施与集成的具体步骤。最后,文章展望了未来市场扩展和技术升级的方向,强调了持续优化和合作的重要性。 适用人群:服装行业的企业管理层、技术负责人、市场和销售团队、供应链管理人员。 使用场景及目标:①通过市场趋势预测和用户偏好分析,提升设计效率和产品创新;②优化供应链管理,减少库存积压和生产浪费;③实现精准营销,提高客户满意度和转化率;④通过智能客服和虚拟试衣技术,提升用户体验;⑤确保数据安全和隐私保护,建立用户信任。 阅读建议:此资源不仅涵盖技术实现的细节,还涉及业务流程的优化和管理策略的调整,建议读者结合实际业务需求,重点关注与自身工作相关的部分,并逐步推进技术的应用和创新。
内容概要:本文详细介绍了一套基于三菱FX3U PLC的完整开发方案,涵盖硬件设计和软件编程两个方面。硬件部分包括详细的原理图、PCB文件以及关键组件的选择和布局技巧,如电源模块、光耦隔离电路、继电器输出等。软件部分则涉及梯形图编程和C语言开发,展示了如何利用GX Works2进行梯形图编程,以及如何使用Keil进行C语言开发,实现复杂的控制逻辑和高效的任务调度。此外,还提供了许多调试技巧和注意事项,帮助开发者避免常见错误并提高开发效率。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对PLC开发感兴趣的初学者和有一定经验的研发人员。 使用场景及目标:适用于需要深入了解PLC底层运作机制、掌握硬件设计和软件编程技能的场合。目标是通过实际案例和详细指导,帮助读者快速上手三菱FX3U PLC的开发,实现高效的控制系统设计。 其他说明:文中提供的代码片段和设计思路不仅有助于理解PLC的工作原理,还可以作为实际项目的参考,加速开发进程。同时,文中还分享了许多实践经验,对于解决实际开发中的问题非常有帮助。
甲壳虫adb助手安全下载.apk
内容概要:本文详细介绍了基于SJA1000协议栈的FPGA实现CAN总线控制器的全过程。涵盖了Verilog和VHDL双版本源码、Altera和Xilinx平台的具体实现细节以及完整的testbench程序。文中深入探讨了状态机控制器、CRC校验器、位时序单元和FIFO缓存四大核心模块的设计思路和技术要点。同时,提供了详细的仿真验证方法和优化技巧,如随机延迟测试、时钟管理配置等。此外,还附带了Quartus II 13.0和ISE14.7的安装指南及常见问题解决方案。 适合人群:FPGA开发者、嵌入式系统工程师、电子工程专业学生及研究人员。 使用场景及目标:适用于希望深入了解CAN总线控制器硬件实现的技术人员,帮助他们快速掌握FPGA开发流程,完成从代码编写到仿真的全流程操作。目标是在实际项目中高效实现CAN总线通信功能,提升系统的稳定性和性能。 其他说明:本文不仅提供完整的工程代码和仿真工具,还包括详细的开发板引脚约束配置和跨平台移植指导,确保用户能够顺利进行开发和调试。
中兴光猫G7610V2-V3.0.0P1N12固件
流变学仿真方法:流变学仿真软件介绍.zip
内容概要:本文详细介绍了如何利用昆仑通态触摸屏与ABB变频器ACS510通过Modbus RTU协议实现直接通讯,构建高效的恒压供水系统。文中涵盖了硬件连接、参数设置、脚本编写、策略配置等方面的内容。通过这种方式,不仅简化了操作流程,还提高了系统的稳定性和可靠性。具体而言,文章首先解释了选择这两者的理由,接着逐步讲解了硬件接线方法、参数配置细节、脚本控制逻辑以及一些常见的调试技巧。此外,还特别提到了夜间降压逻辑、故障复位按钮等高级功能的应用。 适合人群:从事自动化控制系统设计、维护的技术人员,尤其是对恒压供水系统感兴趣的工程师。 使用场景及目标:适用于需要稳定水压供应的场合,如居民小区、商业建筑等。主要目标是通过简化操作流程、提高系统稳定性,从而实现更加智能和高效的供水管理。 其他说明:文章提供了大量实际案例和技术细节,帮助读者更好地理解和应用相关技术。同时,强调了硬件和软件相结合的重要性,分享了许多实用的经验和技巧。
内容概要:本文全面介绍了移动开发的相关知识,首先概述了移动开发的概念及其重要性,随后详细介绍了iOS和Android两大主流平台的开发语言、环境及工具,并涵盖了跨平台开发框架如React Native、Flutter等。接着列举了版本控制、构建自动化、UI设计及调试测试等常用工具。文章还提供了丰富的学习资源,包括官方文档、书籍和视频教程。此外,针对移动开发中常见的性能优化、兼容性、安全性和用户体验设计等问题进行了探讨,并通过社交、电商、健身追踪和地图导航等实际案例展示了不同应用场景的技术实现。最后推荐了一些适合初学者的项目,鼓励读者实践所学知识。; 适合人群:对移动开发感兴趣的初学者,以及希望深入了解移动开发技术的开发者。; 使用场景及目标:①了解iOS和Android平台的开发环境和技术栈;②掌握跨平台开发工具的选择与使用;③学习如何解决移动开发中的性能、兼容性、安全等常见问题;④通过实战案例掌握不同类型应用的核心技术实现。; 其他说明:移动开发是一个不断发展的领域,文中提到的技术和工具可能会随行业发展而更新,建议读者持续关注最新动态并不断学习新技能。
基于python的多种函数递归与斐波那契数列文件
内容概要:本文详细介绍了复盘的概念、操作手法、应用场景及其对企业及个人成长的重要性。复盘源自围棋术语,指对过去的经验进行回顾和反思,以从中学习和改进。文章阐述了复盘的五大核心要素:回顾目标、评估结果、分析原因、总结经验教训和提出改进建议。复盘不仅适用于个人成长,还广泛应用于企业管理和项目管理中,能够帮助企业提升执行力、改善决策流程、优化运营效率,并最终推动组织学习和发展。文中特别强调了复盘在军队、联想集团和英国石油公司(BP)中的成功实践。 适合人群:企业管理者、项目经理、团队领导者及希望提升自我反思和学习能力的职场人士。 使用场景及目标:①帮助个人和团队从过去的经历中吸取教训,避免重复错误;②通过系统的反思和总结,提升团队的协作效率和创新能力;③促进企业内部的知识共享和文化传播,构建学习型组织;④为企业战略调整提供数据支持,确保战略目标的有效落地。 其他说明:为了使复盘成为一种常态化的工作方法和习惯,组织应加强培训,培养专业的引导者,并将复盘融入日常管理流程中。此外,复盘的成功实施还需要营造开放、坦诚的文化氛围,鼓励全员积极参与。复盘不仅仅是回顾过去,更是面向未来的持续改进工具。
内容概要:本文详细介绍了基于三菱FX1S系列PLC和增量式编码器实现卷帘门和提升门自动化控制的程序设计方法。主要内容涵盖硬件配置、程序初始化、编码器信号处理、逻辑控制、速度环控制、防过卷逻辑、急停处理等方面。文中不仅提供了具体的梯形图代码示例,还分享了许多实用的经验和技术细节,如四倍频计数模式、抗干扰措施、速度控制优化等。通过这些设计,实现了系统的高精度、高稳定性和快速响应特性。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC编程和编码器应用有一定基础的人群。 使用场景及目标:适用于需要实现卷帘门或提升门自动化控制的小型工程项目。主要目标是提高系统的稳定性和精确度,减少故障率,延长设备使用寿命。 其他说明:文中提到的实际案例验证了该设计方案的有效性和可靠性,强调了稳定性和实用性在工业控制中的重要性。此外,还提供了一些调试和维护方面的建议,帮助用户更好地理解和应用该技术。
jspm-东风锻造有限公司重大停管理系统 PPT.ppt