简单介绍一下使用tkprof工具调整Oracle SQL语句性能的方法。 —————————– # 用tkprof工具测量执行时间

首先在SQL*Plus中执行以下SQL语句,开启执行记录功能。

alter session set timed_statistics=true;
alter session set sql_trace=true;

然后执行要测量时间的SQL语句:

select 
  user_id, 
  min(site_id) keep (dense_rank first order by dt desc) as site_id
from charlee_test
where site_id in (10,13)
group by user_id

最后关闭记录功能:

alter session set sql_trace=false;
alter session set timed_statistics=false;

这样就记录下了SQL语句的执行log。那么这些log保存在什么地方呢?可以通过以下语句来查看:

select value from v$parameter where name='user_dump_dest';

VALUE
---------------------------------
/opt/oracle/admin/scott/udump

退出SQL*Plus回到shell(或者另开启一个终端),执行如下命令:

ll /opt/oracle/admin/scott/udump/*.trc

利用生成时间找到刚刚生成的log文件,假设为 ora_11111.trc。执行如下命令将该文件转化为可以阅读的格式:

$ tkprof /opt/oracle/admin/scott/udump/ora_11111.trc ora_11111.prf 
  explain=scott/password aggregate=no sys=no sort=fchela

使用文本编辑器打开生成的 ora_11111.prf,内容如下:

********************************************************************************

select user_id, min(site_id) keep (dense_rank first order by dt desc) as site_id
from charlee_test
where site_id in (10,13)
group by user_id

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0          7          0           4
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0          7          0           4

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 61  (WBRRADM)

Rows     Row Source Operation
-------  ---------------------------------------------------
      4  SORT GROUP BY (cr=7 r=0 w=0 time=153 us)
      5   TABLE ACCESS FULL CHARLEE_TEST (cr=7 r=0 w=0 time=68 us)


Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: CHOOSE
      4   SORT (GROUP BY)
      5    TABLE ACCESS (FULL) OF 'CHARLEE_TEST'

该报告的第一部分是执行的SQL语句。第二部分是关于此语句的统计信息,其中各个字段的内容如下:

  • count: OCI进程执行的次数
  • cpu: 消耗的CPU时间
  • elapsed: 总共执行时间
  • disk: 将数据从硬盘读取到缓存中的次数
  • query: number of buffers gotten for consistent read
  • current: number of buffers gotten in current mode
  • rows: 查询返回的行数

下面的Misses in library cache during parse的值为1表明在共有区域中没有找到缓存,因此需要执行该SQL语句。 其下是执行计划以及每一步执行的代价。代价的描述中各个值的含义如下:

  • cr: 从缓存读入的块数
  • r: 从磁盘读入的块数
  • w: 向磁盘写入的块数
  • time: 合计经过的时间

接下来:

Rows     Row Source Operation
-------  ---------------------------------------------------
      6  TABLE ACCESS FULL CHARLEE_TEST (cr=9 r=5 w=0 time=304 us)


Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: CHOOSE
      6   TABLE ACCESS (FULL) OF 'CHARLEE_TEST'

利用Excel将此部分整理,计算相邻两步的时间差,即可知道哪一步占用时间最大。

利用EXPLAIN PLAN语句解释执行计划

SQL语句的执行过程不了解的人,很难明白执行计划的意思。Oracle为我们提供的EXPLAIN PLAN可以将执行计划的详细内容输出。

首先要创建EXPLAIN PLAN语句所需的PLAN_TABLE表。在SQL*Plus中执行以下脚本:

@$ORACLE_HOME/rdbms/admin/utlxplan.sql

然后执行EXPLAIN PLAN:

explain plan for
select 
  user_id, 
  min(site_id) keep (dense_rank first order by dt desc) as site_id
from charlee_test
where site_id in (10,13)
group by user_id

执行下面的脚本可以查看解释结果:

@$ORACLE_HOME/rdbms/admin/utlxpls.sql

----------------------------------------------------------------------
| Id  | Operation            |  Name         | Rows  | Bytes | Cost  |
----------------------------------------------------------------------
|   0 | SELECT STATEMENT     |               |       |       |       |
|   1 |  SORT GROUP BY       |               |       |       |       |
|*  2 |   TABLE ACCESS FULL  | CHARLEE_TEST  |       |       |       |
----------------------------------------------------------------------

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

   2 - filter("CHARLEE_TEST"."SITE_ID"=10 OR
              "CHARLEE_TEST"."SITE_ID"=13)

Note: rule based optimization