2.1 执行计划的基本数据
我们用代码清单2-1中的查询计划为例,解释计划访问中基本数据的含义。
代码清单2-1执行计划查询
HELLODBA.COM>exec sql_explain('select o.owner, o.object_name, o.object_id from t_users u, t_objects o
where u.username=o.owner and o.object_name like :A and u.user_id=:B','BASIC PREDICATE');
Plan hash value: 2133435147
---------------------------------------------------
| Id | Operation | Name |
---------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | NESTED LOOPS | |
| 2 | TABLE ACCESS BY INDEX ROWID| T_USERS |
|* 3 | INDEX UNIQUE SCAN | T_USERS_PK |
|* 4 | TABLE ACCESS FULL | T_OBJECTS |
---------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("U"."USER_ID"=TO_NUMBER(:B))
4 - filter("O"."OBJECT_NAME" LIKE :A AND "U"."USERNAME"="O"."OWNER")
这里利用DBMS_XPLAN显示查询计划,它以表格样式输出查询计划。该表有多个列,其中ID是计划中每个操作的唯一序列号,Operation是每个操作的名称和方式,Name是操作的对象。实际上,该表还有其他一些列代表了优化、统计等信息,我们将在下一节解释这些列的含义。
我们再看每行记录的数据。如果留意看,就不难发现每行数据中的Operation都带有长短不一的前导空格,使之看起来成为一个树状结构。这个结构也就是我们之前提到的操作之间的调用关系。下面分析每一行:
首先看第一条,ID为0,操作为SELECT STATEMENT。这一行实际上只表示这条语句的类型是一条SELECT语句,而非一个真正的操作。因此在一些执行计划的显示当中,没有显示ID为0的操作。
ID为1的操作是NESTED LOOPS,表明它需要对两个数据集以嵌套循环的方式进行数据关联。而这两个数据集则是由其两个子操作2和4分别从表T_USERS和T_OBJECTS上读取得来,也就是说,操作1按顺序调用操作2和4,获取它们返回的数据进行关联。而要实现嵌套循环,就需要两个循环体。其中,操作2就是第一个循环体,也就是外循环;操作4就是第二个循环体,即内循环。
ID为2的操作是TABLE ACCESS BY INDEX ROWID,Name是T_USERS,表明它是通过索引上的ROWID来访问表T_USERS以获取数据。而索引上的ROWID则需要通过其子操作3来获取;
ID为3的操作是INDEX UNIQUE SCAN,Name是T_USERS_PK,表明它是对索引T_USERS_PK进行唯一键值的访问以获取其父操作所需要的ROWID。从之前的DDL语句我们知道,T_USERS_PK是表T_USERS的主键,也是一个唯一索引。而对唯一索引的唯一键值的访问,需要有一个数值的输入作为访问条件。在它的ID列,我们可以留意到*符号,表示这个操作有相关的谓词条件(访问条件或者过滤条件)。而我们这里也特地显示了谓词条件。在下面谓词信息输出部分,可以找到一条信息3 - access("U"."USER_ID"=TO_NUMBER(:B)),表明这是操作ID为3的谓词条件,其中access表示它是访问条件,内容是通过某个数值定位USER_ID键值。
提示:访问条件和过滤条件都属于谓词条件,但它们对操作的作用大不相同。访问条件可以帮助操作从物理对象上定位到符合条件的数据,然后再读取数据;而过滤条件是操作已经从物理存储上读取到了数据,然后将不符合条件的数据过滤掉。它们对语句的性能影响很大,了解了它们之间的差别,就有助于我们对语句进行进一步调优。
ID为4的操作是TABLE ACCESS FULL,Name是T_OBJECTS,表明它是对表T_OBJECTS进行全表扫描。全表扫描即读取表的物理段(Segment)的高水位线(High Water Mark,HWM)以下的所有数据块。同样,它的ID也有*符号,从谓词信息部分可以找到关联的谓词条件4 - filter("O"."OBJECT_NAME" LIKE :A AND "U"."USERNAME"="O"."OWNER")。filter表明它是一个过滤条件,即读取了表T_OBJECTS的所有数据,再过滤掉不符合条件("O"."OBJECT_NAME" LIKE :A AND "U"."USERNAME"="O"."OWNER")的数据。
通过执行计划,我们就可以清楚地了解一条语句是通过什么样的方式读取物理对象的数据,如何对数据进行处理(过滤、排序等),最终获取到符合条件的数据。再结合执行计划中的其他数据,我们就可以进一步定位语句的性能瓶颈在哪里,从而为我们实施优化奠定基础。