查看: 3773|回复: 1

[性能调整] 无法访问SQL代码的优化—OUTLINE的适用性以及DBMS_STATS.set_table_stats

[复制链接]
论坛徽章:
4
授权会员
日期:2008-10-22 16:57:012010新春纪念徽章
日期:2010-03-01 11:20:072011新春纪念徽章
日期:2011-02-18 11:43:35优秀写手
日期:2013-12-18 09:29:14
发表于 2011-3-14 14:42 | 显示全部楼层 |阅读模式
无法访问SQL代码的优化—OUTLINE的适用性以及DBMS_STATS.set_table_stats

在有些时候我们确实会遇到无法或无法立刻通过更改SQL代码实现优化的目的,比如说购买的第三方软件或应用程序,但是对方没有提供源代码,或者虽然是本公司自行开发的软件,但是无法因为没有做到很好的可拔插性如SQL代码嵌入在Java或.net源代码中,导致无法在业务运行的时段内重启应用服务器实现代码的优化,这个时候我们将无法通过hint来实现SQL语句的优化,而必须借助于存储纲要(stored_outline)。存储纲要其实在内部也和hint一样,是一系列和一个特定语句相关的hint,只不过stored_outline是为sql自动产生相关的hint。

本章的目的不是解释存储纲要怎么创建,也不介绍它的语法结构图。关于这方面的信息,读者可以通过google或oracle sql参考手册获得详尽的资料。因此本章的目的是在现实应用中当我们遇到无法通过更改SQL代码实现性能调优时,将如何通过存储纲要进行优化以尽可能(注:虽然使用存储纲要可以优化一些无法更改SQL代码的脚本,但是受其灵活性方面的限制,我们只能做到部分比较复杂的优化,对于十分复杂的语句,通过存储纲要基本上很难做到完全预期的优化,比如说当前脚本运行时间2分钟,目标为5秒钟以内,可能我们只能做到优化后为30秒钟)达到和通过更改SQL语句相同的目标。

虽然存储纲要和hint的目标都一样,优化SQL脚本的性能,但是总的来说两者在完成相同目标的路径上有着很大的不同,通过hint,因为我们可以直接更改sql语句的代码,因此只要掌握了优化的目标和技巧,实现起来就会很顺利。但是如果通过存储纲要要实现相同的优化,根据语句的复杂程度,其所需要付出的代价可能会比使用hint高几倍甚至上百倍。这里我们先来看两种简单的情况,但表查询和两表查询:
1、Select * from scott.emp e where e.empno=888;
2、select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

第一个语句,其执行无非就是在全表扫描和索引扫描以及是否并行执行之间选择,对于这种很简单的情形,如果我们再遇到无法修改代码但是需要优化的情况,往往通过增加、索引,收集、设置统计信息和直方图,以及更改表或索引的默认并行度以及临时更改会话的参数来获得预期的执行计划。
相比第一个语句,第二个语句优化要灵活的多,除了需要考虑优化第一个语句时需要考虑的因素外,还需要考虑表的连接方式,连接顺序,如果通过并行方式进行关联,还需要考虑并行的关联方法是广播方式还是哈希重分布的方式。下面我们来看下第二个语句的最初执行计划:
SQL> set autotrace traceonly explain
SQL> select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

Execution Plan
----------------------------------------------------------
Plan hash value: 575222474

-----------------------------------------------------------------------------------------

| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| T
ime     |

-----------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT             |          |   250 | 14250 |     7  (15)| 00:00:01 |

|   1 |  MERGE JOIN                  |          |   250 | 14250 |     7  (15)| 00:00:01 |

|   2 |   TABLE ACCESS BY INDEX ROWID| EMP      |   100 |  3700 |     2   (0)| 00:00:01 |

|   3 |    INDEX FULL SCAN           | EMP_IDX2 |    14 |       |     1   (0)| 00:00:01 |

|*  4 |   SORT JOIN                  |          |    10 |   200 |     5  (20)| 00:00:01 |

|   5 |    TABLE ACCESS FULL         | DEPT     |    10 |   200 |     4   (0)| 00:00:01 |

--------------------------------------------------------------------------------
---------


Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("E"."DEPTNO"="B"."DEPTNO")
       filter("E"."DEPTNO"="B"."DEPTNO")

我们假设emp表有100w数据,dept表有10w数据,在这种情况下,我们通常希望优化后的执行计划为,emp表和dept表均用全表扫描的方式,采用哈希关联,dept表用于建立哈希。有了目标之后,我们就要考虑具体实施的事情了,首先要实现全表扫描,就要把索引弄掉,如下所示:
alter index scott.emp_idx2 unusable;
把索引设置为不可用而非删除的好处是优化完成后rebuild就可以了,不容易忘记。我们再来看其执行计划,
SQL> select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

Execution Plan
----------------------------------------------------------
Plan hash value: 844388907

--------------------------------------------------------------------------------
--------

| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Ti
me     |

--------------------------------------------------------------------------------
--------

|   0 | SELECT STATEMENT             |         |   250 | 14250 |     7  (15)| 00
:00:01 |

|   1 |  MERGE JOIN                  |         |   250 | 14250 |     7  (15)| 00
:00:01 |

|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |    10 |   200 |     2   (0)| 00
:00:01 |

|   3 |    INDEX FULL SCAN           | PK_DEPT |    10 |       |     1   (0)| 00
:00:01 |

|*  4 |   SORT JOIN                  |         |   100 |  3700 |     5  (20)| 00
:00:01 |

|   5 |    TABLE ACCESS FULL         | EMP     |   100 |  3700 |     4   (0)| 00
:00:01 |

--------------------------------------------------------------------------------
--------


Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("E"."DEPTNO"="B"."DEPTNO")
       filter("E"."DEPTNO"="B"."DEPTNO")

emp表已经全表扫描了,但是dept表还是使用了全索引扫描,所以把pk_dept也临时禁用掉,
alter index scott.pk_dept unusable;

我们再来看下执行计划:
SQL> select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

Execution Plan
----------------------------------------------------------
Plan hash value: 1123238657

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  2500K|   135M|   248  (11)| 00:00:03 |
|*  1 |  HASH JOIN         |      |  2500K|   135M|   248  (11)| 00:00:03 |
|   2 |   TABLE ACCESS FULL| EMP  |   100 |  3700 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| DEPT |   100K|  1953K|   222   (1)| 00:00:03 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("E"."DEPTNO"="B"."DEPTNO")

Ok,差最后一步,dept表作为主表,就完成我们的目标了。哪一张表选择作为驱动表是优化器根据基数计算出来的。既然如此,我们就需要把表或索引的基数设置为能够被优化器认可并且也能让优化器产生我们想要的执行计划的值。这可以通过dbms_stats.set_table_stats来实现,如下所示,我们把dept设置为有10w条记录,把emp设置为有100w条记录:
begin
  dbms_stats.set_table_stats(ownname => 'SCOTT',tabname => 'DEPT',numrows => 100000);
end;
/
begin
  dbms_stats.set_table_stats(ownname => 'SCOTT',tabname => 'EMP',numrows => 1000000);
end;
/
最后,我们再来看下执行计划:
SQL> select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

Execution Plan
----------------------------------------------------------
Plan hash value: 615168685

-----------------------------------------------------------------------------------

| Id  | Operation          | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time  |

-----------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |      |    25G|  1327G|       |   224K (99)| 00:44:52 |

|*  1 |  HASH JOIN         |      |    25G|  1327G|  3128K|   224K (99)| 00:44:52 |

|   2 |   TABLE ACCESS FULL| DEPT |   100K|  1953K|       |   222   (1)| 00:00:03 |

|   3 |   TABLE ACCESS FULL| EMP  |  1000K|    35M|       |   246  (11)| 00:00:03 |

-----------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("E"."DEPTNO"="B"."DEPTNO")

从上面可以看出,这和我们希望的结果完全一致了。

当通过更改优化器统计以及调整索引实现了预期的执行计划之后,接下去要做的就是为语句创建存储纲要,如下所示:
CREATE OUTLINE salaries FOR CATEGORY special on select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

接下去,我们恢复禁用的索引,统计设置,
ALTER INDEX scott.pk_dept REBUILD;
alter index scott.emp_idx2 rebuild;
begin
  dbms_stats.set_table_stats(ownname => 'SCOTT',tabname => 'DEPT',numrows => 10);
end;
/
begin
  dbms_stats.set_table_stats(ownname => 'SCOTT',tabname => 'EMP',numrows => 100);
end;
/

最后,我们来测试一下。先测试不使用存储纲要的情况,
SQL> ALTER session SET USE_STORED_OUTLINES=;

Session altered.

SQL> select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

Execution Plan
----------------------------------------------------------
Plan hash value: 575222474

--------------------------------------------------------------------------------
---------

| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| T
ime     |

--------------------------------------------------------------------------------
---------

|   0 | SELECT STATEMENT             |          |   250 | 14250 |   224   (1)| 00:00:03 |

|   1 |  MERGE JOIN                  |          |   250 | 14250 |   224   (1)| 00:00:03 |

|   2 |   TABLE ACCESS BY INDEX ROWID| EMP      |   100 |  3700 |     2   (0)| 00:00:01 |

|   3 |    INDEX FULL SCAN           | EMP_IDX2 |    14 |       |     1   (0)| 00:00:01 |

|*  4 |   SORT JOIN                  |          |    10 |   200 |   222   (1)| 00:00:03 |

|   5 |    TABLE ACCESS FULL         | DEPT     |    10 |   200 |   221   (1)| 00:00:03 |

--------------------------------------------------------------------------------
---------


Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("E"."DEPTNO"="B"."DEPTNO")
       filter("E"."DEPTNO"="B"."DEPTNO")

我们可以看到又恢复到了原来的执行计划,我们再来看看使用存储纲要的情况:
SQL> ALTER session SET USE_STORED_OUTLINES=special;

Session altered.

SQL> select * from scott.emp e, scott.dept b where e.deptno = b.deptno;

Execution Plan
----------------------------------------------------------
Plan hash value: 615168685

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |   250 | 14250 |   442   (1)| 00:00:06 |
|*  1 |  HASH JOIN         |      |   250 | 14250 |   442   (1)| 00:00:06 |
|   2 |   TABLE ACCESS FULL| DEPT |    10 |   200 |   221   (1)| 00:00:03 |
|   3 |   TABLE ACCESS FULL| EMP  |   100 |  3700 |   221   (1)| 00:00:03 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("E"."DEPTNO"="B"."DEPTNO")

Note
-----
   - outline "SALARIES" used for this statement

语句没有任何的更改,执行计划已经是我们想要的了。

最后,USE_STORED_OUTLINES是一个系统级可以调整的参数,可以通过alter system set USE_STORED_OUTLINES=special;全局更改。这样我们就没有必要使用alter session了,刚才也提到过,因为无法更改代码才这么做,因此,也无法在现有代码中增加alter session这个会话控制语句。

下面我们来看一个比较复杂的语句的优化,虽然通过存储纲要进行调优的时候,其总的还是利用上述的手段实现,但是在真正的实践过程中,我们会发现,我们遇到的很多情况远比上述的要复杂的多。考虑下面的语句,

最后,我们再来看一个例子(这个例子很简单,但是通过存储纲要无法实现)。语句如下:
SQL> set autotrace traceonly explain
SQL> select /*+ use_hash(t1 c) full(c)*/
  2   count(1) as cou
  3    from cb_tasklog tl
  4   inner join cb_client c
  5      on c.id = tl.taskid
  6   where tl.calloutno is not null
  7     and c.activeId = 0
  8     and c.account = 'null'
  9     and tl.currexecdate <= sysdate
10     and tl.currexecdate >= add_months(sysdate, -12);

Execution Plan
----------------------------------------------------------
Plan hash value: 2974031790

-------------------------------------------------------------------------------------

| Id  | Operation            | Name         | Rows  | Bytes | Cost (%CPU)| Time    |

-------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT     |              |     1 |    40 | 19807   (1)| 00:03:58 |

|   1 |  SORT AGGREGATE      |              |     1 |    40 |            ||

|*  2 |   FILTER             |              |       |       |            ||

|*  3 |    HASH JOIN         |              |     1 |    40 | 19807   (1)| 00:03:58 |

|*  4 |     TABLE ACCESS FULL| T_CB_CLIENT  |     1 |    20 | 17648   (1)| 00:03:32|

|*  5 |     TABLE ACCESS FULL| T_CB_TASKLOG |   462K|  9029K|  2156   (3)| 00:00:26 |

-------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
   3 - access("ID"="TASKID")
   4 - filter("ACCOUNT"='null' AND "ACTIVEID"=0)
   5 - filter("CALLOUTNO" IS NOT NULL AND
              "CURREXECDATE">=ADD_MONTHS(SYSDATE@!,-12) AND "CURREXECDATE"<=SYSDATE@!)

这个语句最初是没有account=’null’这个条件的,因此其中的hint在当初优化的时候是没有问题的。但是后来,客户认为总是返回所有用户的数据不是他想要的,所以开发人员增加了这个条件。但是他没有去检查相应的执行计划是否会不合理就直接把升级包发给现场实施人员了,过了一段时间后,一次日常检查时发现这个语句消耗的资源很厉害,查看了执行计划后发现语句已经改过需求,原来的提示已经不适用了,但是因为sql语句是直接写在java中的,应用程序要更改代码需求不仅要重启服务器,还要走升级流程,一路下来绝对是很痛苦的一件事。所以也只能通过存储纲要来解决。

这个语句之所以慢,就是因为它使用哈西连接和全表扫描,几乎95%的LIO都是不必要的,因此首先要做的就是让优化器忽略提示,然后让优化器选择对t_cb_client使用索引扫描,对两个表执行nl连接。第一个问题,让优化器忽略hint,这其实可以通过一个会话级的隐含参数_optimizer_ignore_hints来实现,如下所示:
SQL> alter session set "_optimizer_ignore_hints"=true;

Session altered.

SQL> select /*+ use_hash(t1 c) full(c)*/
  2   count(1) as cou
  3    from cb_tasklog tl
  4   inner join cb_client c
  5      on c.id = tl.taskid
  6   where tl.calloutno is not null
  7     and c.activeId = 0
  8     and c.account = 'null'
  9     and tl.currexecdate <= sysdate
10     and tl.currexecdate >= add_months(sysdate, -12);

Execution Plan
----------------------------------------------------------
Plan hash value: 3927168463

--------------------------------------------------------------------------------------

| Id  | Operation            | Name          | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT     |               |     1 |    40 |  2162   (3)| 00:00:26 |

|   1 |  SORT AGGREGATE      |               |     1 |    40 |            |     |

|*  2 |   FILTER             |               |       |       |            |     |

|*  3 |    HASH JOIN         |               |     1 |    40 |  2162   (3)| 00:00:26 |

|*  4 |     INDEX RANGE SCAN | IDX_CB_CLIENT |     1 |    20 |     3   (0)| 00:00:01 |

|*  5 |     TABLE ACCESS FULL| T_CB_TASKLOG  |   462K|  9029K|  2156   (3)| 00:00:26 |

--------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
   3 - access("ID"="TASKID")
   4 - access("ACCOUNT"='null' AND "ACTIVEID"=0)
   5 - filter("CALLOUTNO" IS NOT NULL AND
              "CURREXECDATE">=ADD_MONTHS(SYSDATE@!,-12) AND "CURREXECDATE"<=SYSDATE@!)

从上文可以看出,优化器已经忽略了嵌入的hint,接下去我们要做的就是让两个表通过nl连接,这可以通过在t_cb_tasklog上创建索引实现,如下所示:
create index t_CB_TASKLOG_idx1 on t_CB_TASKLOG(Taskid);

我们再来看一下新的执行计划:
SQL> select /*+ use_hash(t1 c) full(c)*/
  2   count(1) as cou
  3    from cb_tasklog tl
  4   inner join cb_client c
  5      on c.id = tl.taskid
  6   where tl.calloutno is not null
  7     and c.activeId = 0
  8     and c.account = 'null'
  9     and tl.currexecdate <= sysdate
10     and tl.currexecdate >= add_months(sysdate, -12)
11  ;

Execution Plan
----------------------------------------------------------
Plan hash value: 2113484006

---------------------------------------------------------------------------------------------------

| Id  | Operation                     | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT              |                   |     1 |    40 |6   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE               |                   |     1 |    40 |       |          |

|*  2 |   FILTER                      |                   |       |       |       |          |

|*  3 |    TABLE ACCESS BY INDEX ROWID| T_CB_TASKLOG      |     1 |    20 |3   (0)| 00:00:01 |

|   4 |     NESTED LOOPS              |                   |     1 |    40 |6   (0)| 00:00:01 |

|*  5 |      INDEX RANGE SCAN         | IDX_CB_CLIENT     |     1 |    20 |3   (0)| 00:00:01 |

|*  6 |      INDEX RANGE SCAN         | T_CB_TASKLOG_IDX1 |     1 |       |2   (0)| 00:00:01 |

---------------------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
   3 - filter("CALLOUTNO" IS NOT NULL AND "CURREXECDATE">=ADD_MONTHS(SYSDATE@!,-12) AND "CURREXECDATE"<=SYSDATE@!)
   5 - access("ACCOUNT"='null' AND "ACTIVEID"=0)
   6 - access("ID"="TASKID")

好,到此为止,语句的执行计划已经达到我们的预期了,我们来为其创建存储纲要。
create OUTLINE test1 for category ignore_hint on
select /*+ use_hash(t1 c) full(c) */
count(1) as cou
  from cb_tasklog tl
inner join cb_client c
    on c.id = tl.taskid
where tl.calloutno is not null
   and c.activeId = 0
   and c.account = 'null'
   and tl.currexecdate <= sysdate
   and tl.currexecdate >= add_months(sysdate, -12);

alter system set USE_STORED_OUTLINES=ignore_hint;
alter system set "_optimizer_ignore_hints"=true;

最后,我们来测试下:
SQL> set autotrace traceonly explain
SQL> alter system flush shared_pool;

System altered.

SQL>  select /*+ use_hash(t1 c) full(c) */
  2   count(1) as cou
  3    from cb_tasklog tl
  4   inner join cb_client c
  5      on c.id = tl.taskid
  6   where tl.calloutno is not null
  7     and c.activeId = 0
  8     and c.account = 'null'
  9     and tl.currexecdate <= sysdate
10     and tl.currexecdate >= add_months(sysdate, -12);

Execution Plan
----------------------------------------------------------
Plan hash value: 2113484006

--------------------------------------------------------------------------------
-------------------

| Id  | Operation                     | Name              | Rows  | Bytes | Cost
(%CPU)| Time     |

--------------------------------------------------------------------------------
-------------------

|   0 | SELECT STATEMENT              |                   |     1 |    40 |
3   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE               |                   |     1 |    40 |
       |          |

|*  2 |   FILTER                      |                   |       |       |
       |          |

|*  3 |    TABLE ACCESS BY INDEX ROWID| T_CB_TASKLOG      |     1 |    20 |
3   (0)| 00:00:01 |

|   4 |     NESTED LOOPS              |                   |     1 |    40 |
3   (0)| 00:00:01 |

|*  5 |      INDEX RANGE SCAN         | IDX_CB_CLIENT     |     1 |    20 |
0   (0)| 00:00:01 |

|*  6 |      INDEX RANGE SCAN         | T_CB_TASKLOG_IDX1 |     1 |       |
2   (0)| 00:00:01 |

--------------------------------------------------------------------------------
-------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
   3 - filter("CALLOUTNO" IS NOT NULL AND "CURREXECDATE">=ADD_MONTHS(SYSDATE@!,-
12) AND

              "CURREXECDATE"<=SYSDATE@!)
   5 - access("ACCOUNT"='null' AND "ACTIVEID"=0)
   6 - access("ID"="TASKID")

Note
-----
   - 'PLAN_TABLE' is old version
   - outline "TEST1" used for this statement

现在我们来把_optimizer_ignore_hints设置成false(默认值)看看,
SQL> alter system set "_optimizer_ignore_hints"=false;

System altered.

SQL> alter system set USE_STORED_OUTLINES=ignore_hint;

System altered.

SQL>  select /*+ use_hash(t1 c) full(c) */
  2   count(1) as cou
  3    from cb_tasklog tl
  4   inner join cb_client c
  5      on c.id = tl.taskid
  6   where tl.calloutno is not null
  7     and c.activeId = 0
  8     and c.account = 'null'
  9     and tl.currexecdate <= sysdate
10     and tl.currexecdate >= add_months(sysdate, -12);

Execution Plan
----------------------------------------------------------
Plan hash value: 547531085

--------------------------------------------------------------------------------
-------------------

| Id  | Operation                     | Name              | Rows  | Bytes | Cost
(%CPU)| Time     |

--------------------------------------------------------------------------------
-------------------

|   0 | SELECT STATEMENT              |                   |     1 |    40 |  219
2K  (1)| 07:18:32 |

|   1 |  SORT AGGREGATE               |                   |     1 |    40 |
       |          |

|*  2 |   FILTER                      |                   |       |       |
       |          |

|*  3 |    TABLE ACCESS BY INDEX ROWID| T_CB_TASKLOG      |     1 |    20 |
3   (0)| 00:00:01 |

|   4 |     NESTED LOOPS              |                   |     1 |    40 |  219
2K  (1)| 07:18:32 |

|*  5 |      TABLE ACCESS FULL        | T_CB_CLIENT       |     1 |    20 |  219
2K  (1)| 07:18:32 |

|*  6 |      INDEX RANGE SCAN         | T_CB_TASKLOG_IDX1 |     1 |       |
2   (0)| 00:00:01 |

--------------------------------------------------------------------------------
-------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(SYSDATE@!>=ADD_MONTHS(SYSDATE@!,-12))
   3 - filter("CALLOUTNO" IS NOT NULL AND "CURREXECDATE">=ADD_MONTHS(SYSDATE@!,-
12) AND

              "CURREXECDATE"<=SYSDATE@!)
   5 - filter("ACCOUNT"='null' AND "ACTIVEID"=0)
   6 - access("ID"="TASKID")

Note
-----
   - 'PLAN_TABLE' is old version
   - outline "TEST1" used for this statement

虽然我们从最后一行可以看出,虽然显示了优化器使用了存储纲要,但是从执行计划可以看出,优化器事实上并没有使用存储纲要,也做不了优化,所以存储纲要要求优化器环境也完全相同的情况下才能被重用,所以总的来讲,存储纲要并没有想象中的那么好,这也是我们不推荐将SQL代码嵌入到JAVA或其他语言中的原因。
论坛徽章:
2
2011新春纪念徽章
日期:2011-02-24 22:18:082010广州亚运会纪念徽章:赛艇
日期:2011-03-03 22:29:31
发表于 2011-3-14 19:38 | 显示全部楼层
good

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

SACC2019中国系统架构师大会

【数字转型 架构演进】SACC2019中国系统架构师大会,7折限时优惠重磅来袭!
2019年10月31日~11月2日第11届中国系统架构师大会(SACC2019)将在北京隆重召开。四大主线并行的演讲模式,1个主会场、20个技术专场、超千人参与的会议规模,100+来自互联网、金融、制造业、电商等领域的嘉宾阵容,将为广大参会者提供一场最具价值的技术交流盛会。

限时七折期:2019年8月31日前


----------------------------------------

大会官网>>
TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 
京ICP备09055130号-4  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表