例子:利用格式化的输出文件进行sql调整

第一步: - 现看格式化输出文件最后部分,即汇总部分

===========================================================

OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS

| call | count | cpu | elapsed | disk | query | current | rows |

|--------- |------- |------ |--------- |--------- |-------- |--------- |-------- |

| Parse | [A] 7 | 1.87 | 4.53 | 385 | [G] 553 | 22 | 0 |

| Execute | [E] 7 | 0.03 | 0.11 | [P] 0 | [C] 0 | [D] 0 | [F] 0 |

| Fetch | [E] 6 | 1.39 | 4.21 | [P] 182 | [C] 820 | [D] 3 | [F] 20 |

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

Misses in library cache during parse: 5

Misses in library cache during execute: 1

8 user SQL statements in session.

12 internal SQL statements in session.

[B] 54 SQL statements in session.

3 statements EXPLAINed in this session.


(1)。 通过比较 [A] 与 [B],我们可以发现是否有过量的parsing现象。在上面的例子中,我们可以看到在session中执行了54个语句,但是只有7次parses,所以这是比较正常的,没有过量的parse现象。


(2)。 利用 [P], [C] & [D] 来决定数据库高速缓存的命中率问题

Hit Ratio is logical reads/physical reads:

Logical Reads = Consistent Gets + DB Block Gets

Logical Reads = query + current

Logical Reads = Sum[C] + Sum[D]

Logical Reads = 0+820 + 0+3

Logical Reads = 820 + 3

Logical Reads = 823

Hit Ratio = 1 - (Physical Reads / Logical Reads)

Hit Ratio = 1 - (Sum[P] / Logical Reads)

Hit Ratio = 1 - (128 / 823)

Hit Ratio = 1 - (0.16)

Hit Ratio = 0.84 or 84%


(3)。 我们希望fetch的次数要比rows小,即一次fetch可以取多行数据(array fetching),

可以我们可以更高效的取得查询数据。

这可以通过比较[E]与[F].

[E] = 6 = Number of Fetches

[F] = 20 = Number of Rows

从上面的信息中我们可以看到,6次fetch总共取了20行数据,结果不是很坏。如果使用了经过良好配置arrayfetching,则可以用更少的fetch次数取到同样数量的数据,性能会更好。


(4)。 [G] 表示为了对语句进行分析,读数据字典告诉缓存的次数

- 这个参数对性能的影响不大,一般不用关心。而且这个统计值一般不是我们可以控制的。


第二步 – 检查耗费大量资源的语句

===============================================

update …

where …

| call | count | cpu | elapsed | disk | query | current | rows |

|--------- |------- |----- |--------- |------ |-------- |--------- |-------- |

| Parse | 1 | 7 | 122 | 0 | 0 | 0 | 0 |

| Execute | 1 | 75 | 461 | 5 | [H] 297 | [I] 3 | [J] 1 |

| Fetch | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

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

[H] 表明需要访问297个数据块才能找到我们需要修改的数据。

[I] 表明我们的修改操作才修改3个数据块中的数据

[J] 表明我们只修改了一行数据(其它数据块的修改应为undo、redo信息)为了修改一行数据而要搜寻297个数据块。考虑是否需要在查许的列上建一个索引!


第三步 – 查看是否有过量的parse现象

==============================

select …

| call | count | cpu | elapsed | disk | query | current | rows |

|--------- |------ -|--------- |--------- |----- -|------- -|-------- -|------ -|

| Parse | [M] 2 | [N] 221 | 329 | 0 | 45 | 0 | 0 |

| Execute | [O] 3 | [P] 9 | 17 | 0 | 0 | 0 | 0 |

| Fetch | 3 | 6 | 8 | 0 | [L] 4 | 0 | [K] 1 |

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

Misses in library cache during parse: 2 [Q]

[K] 表明这个查询只返回一行数据

[L] 表明我们需要fetch 4次才能得到数据,这是正常的,因为需要额外的fetch操作以便检查是否fetch到cursor的最后,当然还可能有其它fetch开销。

[M] 表明我们进行了两次parse(包含hard parse 与soft parse) – 这是我们不想看到的,特别是当parse阶段操作耗费cpu资源比execute阶段耗费的cpu资源([O] & [P])多得多得时候。 [Q] 表明这两个parse操作都是hard parse。如果[Q]的值为1,这个语句有一个hard parse,然后跟着一个soft parse(仅仅从库缓存中得到上次分析的信息,比hard parse要高效的多)。


对上面的例子来说,结果并不是特别的坏,因为该语句只执行2次,然而如果对于频繁执行的sql来说,如果几乎每次执行都需要hard parse,则结果就会变的很坏,此时我们说该语句有过量的parse现象(excessive parsing)。

o解决该问题的方法:

- 使用bind variables

- 使shared pool足够大,从而在内存中容纳你执行过的每一条语句,以便下一次可以重用该语句。但这种方法治标不治本,在繁忙的系统中有时会引起ora-04031: unable to allocate %s bytes of shared memory (%s,%s,%s)错误。

- 使用8i新引入的参数cursor_sharing,建议在经过测试后再使用该参数,因为有时使用该参数后会引起系统性能下降


如何降低parse阶段使用的cpu时间

1.Rewrite the application so statements do not continually reparse.

2.Reduce parsing by using the initialization parameter SESSION_CACHED_CURSORS.

3.Use bind variables to reduce parsing.

注意:

记住如果cursor没有被关闭,将在tkprof的输出文件中看不到任何该sql的输出。设置 SQL_TRACE = false并不能关闭PL/SQL 的child cursors,所以要在自己的存储过程中养成及时关闭显式cursor的习惯。令我们高兴的是,在SQL*Plus中,语句一旦执行完毕,该语句对应的cursor也自动关闭了。


oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html