第55期 Oracle数据库查询有多个执行计划的sql

来源:这里教程网 时间:2026-03-03 23:07:27 作者:

在oracle数据库中,一个sql语句有多个执行计划,意味着这个sql语句不稳定,有可能出现有时查询快,有时查询慢,比如这个sql在某一个列上有索引,大家认为有索引了,sql查询肯定会很快,但是即便有索引,但是在oracle数据库中,索引扫描有很多种方式,索引的访问模式有八种。1.INDEX UNIQUE SCAN    效率最高,主键或唯一索引,走树结构。2.INDEX FAST FULL SCAN  读所有块,可以并行访问索引,但输出不按顺序。3.INDEX FULL SCAN      有顺序的输出,不能并行读索引,走链表结构。4.INDEX RANGE SCAN      给定的区间查询,最常见的访问模式。5.INDEX SKIP SCAN       联合索引的第二列为条件,不同值越少的列,越要放在前面。6. SCAN DESCENDING   降序扫描,自动选择降序使用索引。7. index join        索引的连接,通过索引获得全部数据,可以不扫描表。8. bitmap join       索引的位图连接,多个条件上的列都有索引的情况。INDEX UNIQUE SCAN 扫描肯定比INDEX FULL SCAN要快很多。所以一旦一个sql有多个执行计划时,就会出现有时快,有时慢的情况。我们可以使用下面的sql查询发现oracle数据库查询有多个执行计划的sql。

SQL> SELECT
  2      sql_id,
  3      COUNT(DISTINCT plan_hash_value) as plan_count,
  4      COUNT(DISTINCT child_number) as child_count,
  5      SUM(executions) as total_executions,
  6      MIN(ROUND(elapsed_time/NULLIF(executions, 0)/1000000, 4)) as min_avg_elapsed_sec,
  7      MAX(ROUND(elapsed_time/NULLIF(executions, 0)/1000000, 4)) as max_avg_elapsed_sec,
  8      SUBSTR((SELECT sql_text FROM v$sqltext_with_newlines
  9              WHERE sql_id = v.sql_id AND piece = 0), 1, 100) as sql_text_sample
 10  FROM v$sql v
 11  WHERE executions > 0
 12  AND plan_hash_value > 0
 13  GROUP BY sql_id
 14  HAVING COUNT(DISTINCT plan_hash_value) > 1
 15  ORDER BY plan_count DESC, max_avg_elapsed_sec DESC;
 
SQL_ID        PLAN_COUNT CHILD_COUNT TOTAL_EXECUTIONS MIN_AVG_ELAPSED_SEC MAX_AVG_ELAPSED_SEC SQL_TEXT_SAMPLE
------------- ---------- ----------- ---------------- ------------------- ------------------- --------------------------------------------------------------------------------
bbx4agjfr6yrp          2           5              244              0.0011              0.1839 SELECT c.name, c.col#, c.segcol#, c.intcol#, c.type#, c.length,
8vgz0m72d5sp9          2           2                3              0.0158               0.025 with non_existent_objs as (select /*+ materialize */ exp_id, obj
g94wn7w0dr4tp          2           2                2              0.0082              0.0099 delete /* KSXM:CLEAN_PEND_COL *//*+ dynamic_sampling(4) */   fro
8dz7mfwvwtckz          2           2                4              0.0012               0.009 SELECT PNAME, LENGTH(PNAME), QTABLE  FROM SYS.LOADER_PART_INFO
4faa5w420ua14          2           2                2              0.0064              0.0064 delete /* KSXM:CLEAN_PEND_HIST *//*+ dynamic_sampling(4) */   fr
5pazx6dft6hru          2           9             2360              0.0001              0.0043 select o.owner#, o.name, o.namespace, o.obj#, d.d_timestamp,
4rs3f2phhsb80          2           2                3               0.004              0.0041 delete /* KSXM:CLEAN_DML_INF *//*+ dynamic_sampling(4) */    fro
fzsxusp93pxcc          2           4               97              0.0001               0.003 DELETE FROM wri$_adv_rec_actions a
                                                                                                  WHERE a.task_id = :task_
gxrr466g0v9ck          2           2                7              0.0024              0.0026 delete /* KSXM:CLEAN_PEND_TAB *//*+ dynamic_sampling(4) */   fro
a81vzf0fa0q1p          2           2                8              0.0006              0.0026 delete  /* KSXM:CLEAN_PEND_IND *//*+ dynamic_sampling(4) */  fro
9kg6pqttrtda0          2           8             1008              0.0001              0.0024 select p_obj#  from dependency$ d  where d.d_obj#=:1  and not ex
6axhw420xfds6          2           4               89              0.0005               0.002 select unique version from idl_ub1$ where obj# = :1 and version
fnafmumu52s48          2           2               27              0.0004              0.0007 delete /* KSXM:CLEAN_USER_PREF *//*+ dynamic_sampling(4) */   fr
0kxn8zx1svcbp          2           7             2948                   0              0.0004 select distinct policy# from aud_object_opt$ where object# = :1
14 rows selected
SQL>

查询结果中的PLAN_COUNT列表示这个sql有多少个执行计划。SQL_TEXT_SAMPLE是具体的sql语句。因此根据这两个条件可以判断sql的执行情况。可以使用下面的sql查看sql的执行计划

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('bcxdun3fmn0um', 0, 'TYPICAL'));  -- child_number 0
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('bcxdun3fmn0um', 1, 'TYPICAL'));  -- child_number 1
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('bcxdun3fmn0um', 0, 'TYPICAL')); 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  bcxdun3fmn0um, child number 0
-------------------------------------
DELETE FROM "LISMAN"."LIITEMRISKCODEINFO"  WHERE "SERIALNO" = :b0
Plan hash value: 1944287200
--------------------------------------------------------------------------------
| Id  | Operation          | Name                  | Rows  | Bytes | Cost (%CPU)
--------------------------------------------------------------------------------
|   0 | DELETE STATEMENT   |                       |       |       |     2 (100)
|   1 |  DELETE            | LIITEMRISKCODEINFO    |       |       |
|*  2 |   INDEX UNIQUE SCAN| PK_LIITEMRISKCODEINFO |     1 |    19 |     2   (0)
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("SERIALNO"=:B0)
Note
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-----
   - SQL profile coe_bcxdun3fmn0um_1944287200 used for this statement
23 rows selected
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('bcxdun3fmn0um', 1, 'TYPICAL')); 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  bcxdun3fmn0um, child number 0
-------------------------------------
DELETE FROM "LISMAN"."LIITEMRISKCODEINFO"  WHERE "SERIALNO" = :b0
Plan hash value: 1944287200
--------------------------------------------------------------------------------
| Id  | Operation          | Name                  | Rows  | Bytes | Cost (%CPU)
--------------------------------------------------------------------------------
|   0 | DELETE STATEMENT   |                       |       |       |     2 (100)
|   1 |  DELETE            | LIITEMRISKCODEINFO    |       |       |
|*  2 |   INDEX FULL SCAN  | PK_LIITEMRISKCODEINFO |    200|    170|     8   (0)
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("SERIALNO"=:B0)
Note
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-----
   - SQL profile coe_bcxdun3fmn0um_1944287200 used for this statement
23 rows selected

相关推荐