45 123
发新话题
打印

Oracle Database 10g:为 DBA 提供的最佳前 20 位的特性

Oracle Database 10g:为 DBA 提供的最佳前 20 位的特性

TOP

转贴过来就是啦,呵呵

TOP

第 1 周
得到电影而不是图片:闪回版本查询

不需要设置,立即识别对行的所有更改

在 Oracle9i Database 中,我们看到它推出了以闪回查询形式表示的“时间机器”。该特性允许 DBA 看到特定时间的列值,只要在还原段中提供该数据块此前镜像的拷贝即可。但是,闪回查询只提供某时刻数据的固定快照,而不是在两个时间点之间被更改数据的运行状态表示。某些应用程序,如涉及到外币管理的应用程序,可能需要了解一段时期内数值数据的变化,而不仅仅是两个时间点的数值。由于闪回版本查询特性,Oracle Database 10g 能够更方便高效地执行该任务。

查询对表的更改


在本示例中,我使用了一个银行外币管理应用程序。其数据库含有一个名称为 RATES 的表,用于记录特定时间的汇率。
SQL> desc rates
Name              Null?Type
----------------- -------- ------------
CURRENCY                   VARCHAR2(4)
RATE                       NUMBER(15,10)

该表显示 US$ 与各种其他货币的汇率,在 CURRENCY 列中显示。在金融服务行业中,汇率不但在变更时进行更新,而且被记录在历史中。需要这种方式的原因是银行交易可能在“过去时间”生效,以便适应由于汇款而耗费的时间。例如,对于一项在上午 10:12 发生但在上午 9:12 生效的交易,其有效汇率是上午 9:12 的汇率,而不是现在的汇率。

直到现在,唯一的选择是创建一个汇率历史表来存储汇率的变更,然后查询该表是否提供历史记录。另一种选择是在 RATES 表本身中记录特定汇率适用性的开始和结束时间。当发生变更时,现有行中的 END_TIME 列被更新为 SYSDATE,并插入一个具有新汇率的新行,其 END_TIME 为 NULL。

但是在 Oracle Database 10g 中,闪回版本查询特性不需要维护历史表或存储开始和结束时间。使用该特性,您不必进行额外的设置,即可获得某行在过去特定时间的值。

例如,假定该 DBA 在正常业务过程中数次更新汇率 — 甚至删除了某行并重新插入该行:
insert into rates values ('EURO',1.1012);
commit;
update rates set rate = 1.1014;
commit;
update rates set rate = 1.1013;
commit;
delete rates;
commit;
insert into rates values ('EURO',1.1016);
commit;
update rates set rate = 1.1011;
commit;

在进行了这一系列操作后,DBA 将通过以下命令获得 RATE 列的当前提交值
SQL> select * from rates;

CURR       RATE
---- ----------
EURO     1.1011

此输出显示 RATE 的当前值,没有显示从第一次创建该行以来发生的所有变更。这时使用闪回查询,您可以找出给定时间点的值;但我们对构建变更的审计线索更感兴趣 — 有些类似于通过便携式摄像机来记录变更,而不只是在特定点拍摄一系列快照。

以下查询显示了对表所做的更改:
select versions_starttime, versions_endtime, versions_xid,
versions_operation, rate
from rates versions between timestamp minvalue and maxvalue
order by VERSIONS_STARTTIME
/

VERSIONS_STARTTIME     VERSIONS_ENDTIME       VERSIONS_XID     V       RATE
---------------------- ---------------------- ---------------- - ----------
01-DEC-03 03.57.12 PM  01-DEC-03 03.57.30 PM  0002002800000C61 I     1.1012
01-DEC-03 03.57.30 PM  01-DEC-03 03.57.39 PM  000A000A00000029 U     1.1014
01-DEC-03 03.57.39 PM  01-DEC-03 03.57.55 PM  000A000B00000029 U     1.1013
01-DEC-03 03.57.55 PM                         000A000C00000029 D     1.1013
01-DEC-03 03.58.07 PM  01-DEC-03 03.58.17 PM  000A000D00000029 I     1.1016
01-DEC-03 03.58.17 PM                         000A000E00000029 U     1.1011

注意,此处显示了对该行所作的所有更改,甚至包括该行被删除和重新插入的情况。VERSION_OPERATION 列显示对该行执行了什么操作 (Insert/Update/Delete)。所做的这些工作不需要历史表或额外的列。

在上述查询中,列 versions_starttime、versions_endtime、versions_xid、versions_operation 是伪列,与 ROWNUM、LEVEL 等其他熟悉的伪列相类似。其他伪列 — 如 VERSIONS_STARTSCN 和 VERSIONS_ENDSCN — 显示了该时刻的系统更改号。列 versions_xid 显示了更改该行的事务标识符。有关该事务的更多详细信息可在视图 FLASHBACK_TRANSACTION_QUERY 中找到,其中列 XID 显示事务 id。例如,使用上述的 VERSIONS_XID 值 000A000D00000029,UNDO_SQL 值显示了实际的语句。
SELECT UNDO_SQL
FROM FLASHBACK_TRANSACTION_QUERY
WHERE XID = '000A000D00000029';

UNDO_SQL
----------------------------------------------------------------------------
insert into "ANANDA"."RATES"("CURRENCY","RATE") values ('EURO','1.1013');

除了实际语句之外,该视图还显示提交操作的时间标记和 SCN、查询开始时的 SCN 和时间标记以及其他信息。

找出一段时期中的变更

现在,让我们来看如何有效地使用这些信息。假设我们需要找出下午 3:57:54 时 RATE 列的值。我们可以执行:
select rate, versions_starttime, versions_endtime
from rates versions
between timestamp
to_date('12/1/2003 15:57:54','mm/dd/yyyy hh24:mi:ss')
and to_date('12/1/2003 16:57:55','mm/dd/yyyy hh24:mi:ss')
/

RATE VERSIONS_STARTTIME     VERSIONS_ENDTIME
---------- ---------------------- ----------------------
    1.1011

此查询与闪回查询类似。在以上的示例中,开始和结束时间为空,表示汇率在该时间段中没有更改,而是包含一个时间段。还可以使用 SCN 来找出过去的版本值。可以从伪列 VERSIONS_STARTSCN 和 VERSIONS_ENDSCN 中获得 SCN 号。以下是一个示例:
select rate, versions_starttime, versions_endtime
from rates versions
between scn 1000 and 1001
/

使用关键词 MINVALUE 和 MAXVALUE,可以显示还原段中提供的所有变更。您甚至可以提供一个特定的日期或 SCN 值作为范围的一个端点,而另一个端点是文字 MAXVALUE 或 MINVALUE。例如,以下查询提供那些只从下午 3:57:52 开始的变更,而不是全部范围的变更:
select versions_starttime, versions_endtime, versions_xid,
versions_operation, rate
from rates versions between timestamp
to_date('12/11/2003 15:57:52', 'mm/dd/yyyy hh24:mi:ss')
and maxvalue
order by VERSIONS_STARTTIME
/

VERSIONS_STARTTIME     VERSIONS_ENDTIME       VERSIONS_XID     V       RATE
---------------------- ---------------------- ---------------- - ----------
01-DEC-03 03.57.55 PM                         000A000C00000029 D     1.1013
01-DEC-03 03.58.07 PM  01-DEC-03 03.58.17 PM  000A000D00000029 I     1.1016
01-DEC-03 03.58.17 PM                         000A000E00000029 U     1.1011

最终的分析

闪回版本查询随取随用地复制表变更的短期易变数值审计。这一优点使得 DBA 能够获得过去时间段中的所有变更而不是特定值,只要还原段中提供数据,就可以尽情使用。因此,最大的可用版本依赖于 UNDO_RETENTION 参数。
有关闪回版本查询的更多信息,请参见 Oracle Database Concepts 10g Release 1 (10.1) 指南的相关部分。

TOP

第 2 周
还要多长时间?:回滚监视

为用户提供对回滚操作时间的准确评估

我们还在这地方吗?还要多长时间?

听起来熟悉吗?这些问题可能是您在前往孩子们最喜爱的主题公园的路上,从汽车后座上提出来的,并且经常是不断地、越来越频繁地提出来。您不想告诉他们还确切需要多长时间吗 — 或者更简单些,您自己知道答案吗?


同样,在回滚长期运行的事务时,经常会有些用户不停地询问相同的问题。这些问题是合理的,因为该事务进行了锁定,正常的处理经常受到回滚进程的影响。

在 Oracle 9i Database 及更低的版本中,您可以执行查询
SELECT USED_UREC
FROM V$TRANSACTION;

该语句返回由当前事务所使用的重做记录的数量,而如果重复地执行该语句,将会显示连续减少的数值,因为回滚进程在其处理过程中会释放重做记录。随后您可以通过对一段间隔进行快照来计算其速率,然后推断出评估结束时间的结果。

虽然在视图 V$TRANSACTION 中有一个名为 START_TIME 的列,但该列只显示整个事务的起始时间(也就是在回滚执行之前)。因此,除了推断,您没有办法知道回滚实际上是在什么时间执行的。

事务回滚的扩展统计信息

在 Oracle Database 10g 中,这种操作很简单。当事务回滚时,事件被记录在视图 V$SESSION_LONGOPS 中,该视图显示长期运行的事务。用于回滚,如果进程耗时超过六秒,则记录出现在该视图中。在回滚执行以后,您可能会隐藏所查看的监视屏幕并执行以下的查询:
select time_remaining
from v$session_longops
where sid = <sid of the session doing the rollback>;

既然您意识到这个视图 V$SESSION_LONGOPS 的重要性,就让我们来看它必须提供的其他信息。该视图在 Oracle Database 10g 的预览版中提供,但没有捕获关于回滚事务的信息。为了以一种易读的方式显示所有的列,我们将使用由 Tom Kyte 在 AskTom.com 中所描述的 PRINT_TABLE 函数。此过程简单地以表格方式而不是常用的行方式来显示列。
SQL> set serveroutput on size 999999
SQL> exec print_table('select * from v$session_longops where sid = 9')
SID : 9
SERIAL#                       : 68
OPNAME                        ransaction Rollback
TARGET                        :
TARGET_DESC                   :xid:0x000e.01c.00000067
SOFAR                         : 20554
TOTALWORK                     : 10234
UNITS                         :Blocks
START_TIME                    :07-dec-2003 21:20:07
LAST_UPDATE_TIME              :07-dec-2003 21:21:24
TIME_REMAINING                : 77
ELAPSED_SECONDS               : 77
CONTEXT                       : 0
MESSAGE                       ransaction Rollback:xid:0x000e.01c.00000067 :
10234 out of 20554 Blocks done
USERNAME                      :SYS
SQL_ADDRESS                   :00000003B719ED08
SQL_HASH_VALUE                : 1430203031
SQL_ID                        :306w9c5amyanr
QCSID                         : 0

注意,此处显示对行的所有更改,即使删除并重新插入行时也是如此。VERSION_OPERATION 列显示对该行执行的操作 (Insert/Update/Delete)。完成这些操作不需要历史表或额外的列。

让我们仔细检查这些列中的每一列。在会话中可能会有超过多个长期运行操作 — 特别是因为视图中包含以前的会话中所有长期运行操作的历史。列 OPNAME 显示该记录用于“事务回滚”,这为我们指出了正确的方向。列 TIME_REMAINING 显示所评估的剩余时间秒数,这在前面已经描述过,而列 ELAPSED_SECONDS 显示到目前为止所消耗的时间。

那么该表如何提供对剩余时间的评估呢?可以在列 TOTALWORK 中找到线索,该列显示要完成的“工作”总量,还有 SOFAR 显示到目前为止已经完成了多少工作。工作的单位显示在列 UNITS 中。在本例中以数据块为单位;因此,到目前为止已经回滚了 20,554 个数据块中共计 10,234 个数据块。此操作到目前为止已消耗了 77 秒。因此,剩余数据块将消耗:

77 * ( 10234 / (20554-10234) ) ˜ 77 秒

但您不必利用这种方法来获得该数值,它已经清楚地显示出来了。最后,列 LAST_UPDATE_TIME 显示有关当前视图内容的时间,这将用于加强您对结果的解释。

SQL 语句

另一部分重要的新信息是正在被回滚的 SQL 语句的标识符。在早先,SQL_ADDRESS 和 SQL_HASH_VALUE 用于获取正在被回滚的 SQL 语句。新的列 SQL_ID 对应于视图 V$SQL 的 SQL_ID,如下所示:
SELECT SQL_TEXT
FROM V$SQL
WHERE SQL_ID = <value of SQL_ID from V$SESSION_LONGOPS>;

该查询返回所回滚的语句,因此提供了额外的校验以及 SQL 语句的地址和散列值。

并行实例恢复

如果 DML 操作是并行操作,则列 QCSID 显示并行查询服务器会话的 SID。在并行回滚事件中,如实例恢复以及随后的故障事务恢复期间,经常用到该信息经常。

例如,假设在大型的更新期间,实例异常关闭。当实例启动时,发生故障的事务被回滚。如果启用了用于并行恢复的初始化参数值,则回滚并行地而不是串行地发生,如同它发生在常规事务回滚中一样。下一步的任务是评估回滚进程的完成时间。

视图 V$FAST_START_TRANSACTIONS 显示为回滚故障事务所产生的事务。类似的视图 V$FAST_START_SERVERS 显示对回滚进行处理的并行查询服务器的数量。这两个视图都在以前的版本中提供,但显示事务标识符的新列 XID 使得联接更方便了。在 Oracle9i Database 以及更低的版本中,您必须通过三列(USN — 重做段号,SLT — 重做段中的存储区号,SEQ — 序列号)来联接视图。其父集显示在 PARENTUSN、PARENTSLT 和 PARENTSEQ 中。在 Oracle Database 10g 中,您只需将其联接到 XID 列,其父 XID 由直观的名称表示:PXID。

最有用的信息部分来自于 V$FAST_START_TRANSACTIONS 视图中的列 RCVSERVERS。如果发生并行回滚,则该列中显示并行查询服务器的数量。您可以查看该列,了解启动了多少并行查询进程:
select rcvservers from v$fast_start_transactions;

如果输出是 1,则事务正在由 SMON 进程进行串行回滚 — 显然这是完成工作的一种不充分的方法。您可以将初始化参数 RECOVERY_PARALLELISM 的值改为除 0 或 1 以外的值,重新启动实例进行并行回滚。随后您可以执行 ALTER SYSTEM SET FAST_START_PARALLEL_ROLLBACK = HIGH,按 CPU 数量的 4 倍创建并行服务器。

如果上述查询的输出显示不是 1,则正在进行并行回滚。您可以查询同一视图 (V$FAST_START_TRANSACTIONS) 来获得父事务和子事务(父事务 id — PXID,而子事务 id — XID)。XID 还可用于联接此视图与 V$FAST_START_SERVERS,以获得其他详细信息。

结论

总之,当在 Oracle Database 10g 中回滚长期运行的事务时 — 无论是并行实例恢复会话还是用户执行的回滚语句 — 您所需做的一切就是查看视图 V$SESSION_LONGOPS 并评估还需要多少时间。

现在,如果能预测到达主题公园的时间就好了!

TOP

第 3 周
名字中包含了什么?:改善的表空间管理

表空间管理得到了重大的改进,这可以归因于一个 sparser SYSTEM、为用户定义一个默认表空间的支持、新的 SYSAUX、甚至重命名

您曾经多少次因用户在 SYSTEM 表空间中创建了非 SYS 和 SYSTEM 的段而伤透脑筋?

在 Oracle9i Database 之前,如果在创建用户时没有指定默认表空间,那么它将默认为 SYSTEM 表空间。如果用户在创建一个段时没有显式地指定一个表空间,那么这个段将在 SYSTEM 中创建—前提是用户在 SYSTEM 表空间中拥有配额(要么显式地授予,要么通过系统权限 UNLIMITED TABLESPACE 来授予)。Oracle9i 允许 DBA 为所有未用显式的临时表空间子句创建的用户指定一个默认的临时表空间,从而减少了这个问题。

在 Oracle Database 10g 中,您可以类似地为用户指定一个默认表空间。在数据库创建期间,CREATE DATABASE 命令可以包含子句 DEFAULT TABLESPACE 。在创建之后,您可以通过发出以下命令来使一个表空间变成默认表空间


ALTER DATABASE DEFAULT TABLESPACE <tsname>;


未用 DEFAULT TABLESPACE 子句创建的所有用户将以 作为它们的默认表空间。您可以在任何时候通过这个 ALTER 命令来改变默认表空间,从而允许您在不同的节点上将不同的表空间指定为默认表空间。

重要注意事项:拥有旧的表空间的所有用户的默认表空间都被修改为 ,即使有些表空间是为某些用户显式指定的。例如,假定用户 USER1 和 USER2 的表空间分别是 TS1 和 TS2 — 它们是在用户创建期间显式指定的。数据库当前的默认表空间是 TS2,但之后,数据库的默认表空间变为 TS1。即使 USER2 的默认表空间是显式指定为 TS2 的,它也将变为 TS1。小心这种边界效应!

如果在数据库创建期间没有指定默认表空间,它将默认为 SYSTEM。但您如何才能知道现有的数据库的默认表空间是哪一个?发出以下查询:


SELECT PROPERTY_VALUE
FROM DATABASE_PROPERTIES
WHERE PROPERTY_NAME = 'DEFAULT_PERMANENT_TABLESPACE';


DATABASE_PROPERTIES 视图显示默认表空间之外,还显示一些非常重要的信息 — 例如默认临时表空间、全局数据库名、时区等。

非必要模式的默认表空间

几种模式(如智能代理用户 DBSNMP、数据挖掘用户 ODM)与用户操作不直接相关,但对数据库完整性仍很重要。这些模式中的一些曾经用 SYSTEM 作为它们的默认表空间 — 这是在 SYSTEM 表空间内对象增殖的又一个原因。

Oracle Database 10g 引进了一个新的称为 SYSAUX 的表空间,它用来保存这些模式的对象。这个表空间是在数据库创建期间自动创建的,并在本地进行管理。唯一允许修改的是数据文件的名称。

这种方法在 SYSTEM 损坏需要完整的数据库恢复时,为恢复提供支持。SYSAUX 中的对象可以被恢复为任意正常的用户对象,同时数据库本身保持运行。

但如果您想将 SYSAUX 中的这些模式中的一些转移到一个不同的表空间中时,该怎么办?例如,考虑 LogMiner 使用的对象,这些对象的大小经常增长,直到最终填满表空间。出于可管理性的原因,您可能考虑将它们转移到它们自己的表空间中。但实现这一目的的最好的方法是什么?

作为一个数据库管理员,了解转移这些特殊对象的正确过程对您而言是很重要的。幸运的是,Oracle Database 10g 提供了一个新的视图使要凭猜测来做的工作形象化。这个视图,V$SYSAUX_OCCUPANTS,列出了表空间 SYSAUX 中的模式的名称、它们的说明、当前使用的空间,以及如何转移它们。(参见表 1。)

注意 LogMiner 如何被清楚地显示为占用 7,488 KB 的空间。它归模式 SYSTEM 所有,而要转移对象,您需要执行打包的过程 SYS.DBMS_LOGMNR_D.SET_TABLESPACE。不过,对于 STATSPACK 对象,这个视图推荐使用导入/导出方法;而对于流,没有转移过程 — 因而您不能容易地将它们从 SYSAUX 表空间中转移出来。列 MOVE_PROCEDURE 默认显示 SYSAUX 中存在的几乎所有工具的正确的转移过程。也可以逆向使用转移过程来使对象回到 SYSAUX 表空间中。

重命名一个表空间

在数据仓库环境中(典型地,对于数据中心体系结构),在数据库之间传输表空间是很常见的。但源数据库和目标数据库必须不存在拥有相同名称的表空间。如果存在两个拥有相同名称的表空间,则目标表空间中的段必须转移到一个不同的表空间中,然后重新创建这个表空间— 这个任务说起来容易做起来难。

Oracle Database 10g 提供了一个方便的解决方案:您可以用以下命令来简单地重命名一个现有的表空间(SYSTEM 和 SYSAUX 除外) — 无论是永久表空间还是临时表空间:


ALTER TABLESPACE <ldname> RENAME TO <newname>;


这个功能还将应用在存档过程中。假定您有一个按范围分区的表,用于记录销售历史数据,每个月的这个分区位于按这个月份命名的一个表空间中 — 例如,1 月份的分区命名为 JAN,并位于一个名称为 JAN 的表空间中。这样您就拥有了一个将信息保留 12 个月的策略。在 2004 年 1 月,您将能够存档 2003 年 1 月的数据。大致的操作流程类似于以下操作:


利用 ALTER TABLE EXCHANGE PARTITION 从分区 JAN 中创建一个独立的表 JAN03。
将表空间重命名为 JAN03。
为表空间 JAN03 创建一个可传输表空间集。
将表空间 JAN03 重新命名为 JAN。
将空的分区交换回表中。

第 1、2、4 和 5 步很简单,并且不会过度地消耗资源(如重做和撤消空间)。第 3 步只是拷贝文件并只为 JAN03 输出数据字典信息,这也是个非常轻松的过程。如果您需要恢复之前存档的分区,这个过程也非常简单,您只需要将相同的过程反过来就行了。

Oracle Database 10g 在处理这些重命名的方式上相当智能化。如果您重命名作为 UNDO 或默认临时表空间的表空间,这可能产生混淆。但数据库将自动调整必要的记录来反映这种变化。例如,将默认表空间的名称从 USERS 修改为 USER_DATA 将自动修改视图 DATABASE_PROPERTIES。在修改之前,查询:


select property_value from database_properties
where property_name = 'DEFAULT_PERMANENT_TABLESPACE';


返回 USERS。在运行下面的语句之后


alter tablespace users rename to user_data;


上述查询返回 USER_DATA,因为所有对 USERS 的引用都被修改为到 USER_DATA。

修改默认临时表空间的情况一样。甚至修改 UNDO 表空间的名称也将触发 SPFILE 中的变化,如下所示:


SQL> select value from v$spparameter where name = 'undo_tablespace';

VALUE
--------
UNDOTBS1

SQL> alter tablespace undotbs1 rename to undotbs;

Tablespace altered.

SQL> select value from v$spparameter where name = 'undo_tablespace';

VALUE
--------
UNDOTBS


结论

在最近的几个 Oracle 版本演变的过程中,对象处理得到了稳定的增强。Oracle8i 引进了表从一个表空间到另一个表空间的转移,Oracle 9i Database R2 引进了列重命名,现在 — 在最新的版本中 — 表空间自身的重命名成为可能。这些增强显著地减轻了数据库管理员的任务 — 特别是在数据仓库或数据中心环境中。

TOP

第 4 周
高速的导出/导入:Oracle Data Pump

利用 Oracle Database 10g 实用工具数据移动得到了很大的提高。

迄今为止,导出/导入工具集仍是跨多个平台转移数据所需劳动强度最小的首选实用工具,尽管人们常常抱怨它速度太慢。导入只是将每条记录从导出转储文件中读出来,然后使用常见的 INSERT INTO 命令将其插入到目标表中,因此导入可能是个很慢的过程,这一点并不让人感到吃惊。

进入 Oracle Data Pump,Oracle Database 10g 中的导出/导入工具包的更新更快的同类工具,它被设计来成倍地加速这个过程。

Data Pump 反映了整个导出/导入过程的彻底革新。它不是使用常见的 SQL 命令,而是应用专用 API 来以更快得多的速度加载和卸载数据。在我的测试中,我看到导出性能比在直接模式下提高了 10-15 倍,导入过程性能提高了 5 倍。此外,与使用导出实用工具不同,它还能够只取出特定类型的对象(如过程)。

Data Pump 导出

这个新的实用工具称为 expdp,以和原来的导出 exp 区分开。在本例中,我们将用 Data Pump 来导出一个大表 CASES,大小约为 3GB。Data Pump 在服务器端使用文件处理来创建和读取文件;因此,目录作为位置使用。在这种情况下,我们将使用文件系统 /u02/dpdata1 来保存转储文件。


create directory dpdata1 as '/u02/dpdata1';
grant read, write on directory dpdata1 to ananda;


接下来,我们将导出数据:


expdp ananda/abc123 tables=CASES directory=DPDATA1
dumpfile=expCASES.dmp job_name=CASES_EXPORT


让我们来分析该命令的各个部分。用户 ID/口令组合、表和转储文件参数的意义是显而易见的。与原来的导出不同,文件是在服务器(不是客户端)上创建的。位置由目录参数值 DPDATA1 指定,它指向之前创建的 /u02/dpdata1。这个进程还在目录参数指定的位置上创建一个日志文件(同样在服务器上)。默认地,这个进程使用一个名称为 DPUMP_DIR 的目录;因此可以创建它来代替 DPDATA1。

注意上面的参数 job_name,这是个特殊的参数,在原来的导出中没有。所有的 Data Pump 工作都通过作业来完成。Data Pump 作业 — 与 DBMS 作业不同 — 只是服务器进程,它代表主进程处理数据。主进程(称为主控制进程)通过高级队列 (AQ) 来协调这项工作;它通过在运行期内创建的一个特殊的表(称为主表)来实现这个目的。在我们的例子中,如果您在 expdp 运行时检查用户 ANANDA 的模式 ,您将注意到一个表 CASES_EXPORT 的存在(对应参数 job_name)。当 expdp 结束时,这个表被丢弃。

导出监控

当 Data Pump Export (DPE) 运行时,按 Control-C;它将阻止消息在屏幕上显示,但不停止导出进程本身。相反,它将显示 DPE 提示符(如下所示)。进程现在被认为处于“交互式”模式:


Export>


这种方法允许在这个 DPE 作业上输入几条命令。要查看概要,在提示符下使用 STATUS 命令:


Export> status
Job:CASES_EXPORT
Operation:EXPORT                        
ModeABLE                          
State:EXECUTING                     
Degree: 1
Job Error Count: 0
Dump file:/u02/dpdata1/expCASES.dmp
bytes written =  2048

Worker 1 Status:
State:EXECUTING                     
Object SchemaWOWNER
Object Name:CASES
Object TypeABLE_EXPORT/TBL_TABLE_DATA/TABLE/TABLE_DATA
Completed Objects: 1
Total Objects: 1
Completed Rows: 4687818


记住,这只是状态显示。导出在后台工作。要继续在屏幕上查看消息,从 Export> 提示符下使用命令 CONTINUE_CLIENT。

并行操作

您可以通过 PARALLEL 参数为导出使用一个以上的线程来显著地加速作业。每个线程创建一个单独的转储文件,因此参数 dumpfile 应当拥有和并行度一样多的项目。您可以指定通配符作为文件名,而不是显式地输入各个文件名,例如:


expdp ananda/abc123 tables=CASES directory=DPDATA1
dumpfile=expCASES_%U.dmp parallel=4 job_name=Cases_Export


注意 dumpfile 参数拥有一个通配符 %U,它指示文件将按需要创建,格式将为 expCASES_nn.dmp,其中 nn 从 01 开始,然后按需要向上增加。

在并行模式下,状态屏幕将显示四个工作进程。(在默认模式下,只有一个进程是可见的。)所有的工作进程同步取出数据,并在状态屏幕上显示它们的进度。

分离访问数据文件和转储目录文件系统的输入/输出通道是很重要的。否则,与维护 Data Pump 作业相关的开销可能超过并行线程的效益,并因此而降低性能。并行方式只有在表的数量多于并行值并且表很大时才是有效的。

数据库监控

您还可以从数据库视图获得关于运行的 Data Pump 作业的更多信息。监控作业的主视图是 DBA_DATAPUMP_JOBS,它将告诉您在作业上有多少个工作进程(列 DEGREE)在工作。另一个重要的视图是 DBA_DATAPUMP_SESSIONS,当它与上述视图和 V$SESSION 结合时将给出主前台进程的会话 SID。

select sid, serial#
from v$session s, dba_datapump_sessions d
where s.saddr = d.saddr;


这条指令显示前台进程的会话。更多有用的信息可以从警报日志中获得。当进程启动时,MCP 和工作进程在警报日志中显示如下:

kupprdp:master process DM00 started with pid=23, OS id=20530 to execute -
SYS.KUPM$MCP.MAIN('CASES_EXPORT', 'ANANDA');

kupprdp:worker process DW01 started with worker id=1, pid=24, OS id=20532 to execute -
SYS.KUPW$WORKER.MAIN('CASES_EXPORT', 'ANANDA');

kupprdp:worker process DW03 started with worker id=2, pid=25, OS id=20534 to execute -
SYS.KUPW$WORKER.MAIN('CASES_EXPORT', 'ANANDA');


它显示为数据泵操作启动的会话的 PID。您可以用以下查询找到实际的 SID:

select sid, program from v$session where paddr in
(select addr from v$process where pid in (23,24,25));


PROGRAM 列将对应警报日志文件中的名称显示进程 DM (为主进程)或 DW (为工作进程)。如果一个工作进程使用了并行查询,比如说 SID 23,您可以在视图 V$PX_SESSION 中看到它,并把它找出来。它将为您显示从 SID 23 代表的工作进程中运行的所有并行查询会话:

select sid from v$px_session where qcsid = 23;


从视图 V$SESSION_LONGOPS 中可以获得其它的有用信息来预测完成作业将花费的时间。

select sid, serial#, sofar, totalwork
from v$session_longops
where opname = 'CASES_EXPORT'
and sofar != totalwork;


列 totalwork 显示总工作量,该列的 sofar 数量被加和到当前的时刻 — 因而您可以用它来估计还要花多长时间。

Data Pump 导入

不过,数据导入性能是 Data Pump 真正出色的地方。要导入先前导出的数据,我们将使用

impdp ananda/abc123 directory=dpdata1 dumpfile=expCASES.dmp job_name=cases_import


导入进程的默认行为是创建表和所有相关的对象,然后在表已存在时产生一个错误。如果您想把数据添加到一个现有的表中,您可以在上述命令行中使用 TABLE_EXISTS_ACTION=APPEND。

和使用 Data Pump 导入一样,在进程中按 Control-C 将进入 Date Pump Import (DPI) 的交互模式;同样,提示符是 Import>。

处理特定对象

您是否有过只需要从一个用户导出特定的过程,以在一个不同的数据库或用户中重新创建这些过程的情况?与传统的导出实用工具不同,Data Pump 允许您只导出特定类型的对象。例如,以下命令让您只导出过程,而不导出其它任何东西 — 不导出表、视图、甚至函数:

expdp ananda/iclaim directory=DPDATA1 dumpfile=expprocs.dmp include=PROCEDURE


要只导出一些特定的对象 — 比如说,函数 FUNC1 和过程 PROC1 — 您可以使用

expdp ananda/iclaim directory=DPDATA1 dumpfile=expprocs.dmp
include=PROCEDURE:\"=\'PROC1\'\",FUNCTION:\"=\'FUNC1\'\"


这个转储文件充当了源对象的一个备份。您甚至可以用它来创建 DDL 脚本,以供之后使用。一个称为 SQLFILE 的特殊参数允许创建 DDL 脚本文件。

impdp ananda/iclaim directory=DPDATA1 dumpfile=expprocs.dmp sqlfile=procs.sql


该指令在 DPDATA1 指定的目录中创建一个名称为 procs.sql 的文件,并将对象的脚本包含在导出转储文件中。这种方法帮助您快速地在另一个模式中创建源对象。

利用参数 INCLUDE 允许您从转储文件中定义要包含或排除的对象。您可以使用子句 INCLUDE=TABLE:"LIKE 'TAB%'" 来仅导出那些名称以 TAB 开头的表。类似地,您可以使用结构 INCLUDE=TABLE:"NOT LIKE 'TAB%'" 来排除所有名称以 TAB 开头的表。作为另一种选择,您可以使用 EXCLUDE 参数来排除特定的对象。

通过外部表,Data Pump 还可以用来传输表空间;它非常强大,能够即时地重定义并行方式,将更多的表添加到一个现有的进程中等等(这超出了本文的范围;关于更多详细信息,请参考 Oracle Database Utilities 10g Release 1 10.1)。以下命令显示Data Pump 导出实用工具提供的所有参数的列表:

expdp help=y


类似地,impdp help=y 将显示 DPI 中的所有参数。

当 Data Pump 作业在运行时,您可以通过在 DPE 或 DPI 提示符下发出 STOP_JOB 来暂停它们,然后用 START_JOB 来重起它们。这个功能在您空间不足和想在继续执行之前进行修改时非常方便。

TOP

收下~◎~◎资料多啊~◎嘿嘿
still waters run deep~

TOP

好东西好东西,继续继续

TOP

好!

:tian

TOP

以前看过,但是没所有收藏,后来想找还一下找不到,谢谢,幸亏贴过来了。

TOP

TOP

支持一下

TOP

我也来灌点水

第 5 周
闪回表

使用 Oracle Database 10g 中的闪回表特性,可以毫不费力地恢复被意外删除的表

以下是一个不该发生却经常发生的情况:用户删除了一个非常重要的表 — 当然是意外地删除 — 并需要尽快地恢复。(在某些时候,这个不幸的用户可能就是 DBA!)

Oracle9i Database 推出了闪回查询选项的概念,以便检索过去某个时间点的数据,但它不能闪回 DDL 操作,如删除表的操作。唯一的恢复方法是在另一个数据库中使用表空间的时间点恢复,然后使用导出/导入或其他方法,在当前数据库中重新创建表。这一过程需要 DBA 进行大量工作并且耗费宝贵的时间,更不用说还要使用另一个数据库进行克隆。

请使用 Oracle Database 10g 中的闪回表特性,它使得被删除表的恢复过程如同执行几条语句一样简单。让我们来看该特性是如何工作的。


删除那个表!

首先,让我们查看当前模式中的表。


SQL> select * from tab;

TNAME                    TABTYPE  CLUSTERID
------------------------ ------- ----------
RECYCLETEST              TABLE


现在,我们意外地删除了该表:


SQL> drop table recycletest;

Table dropped.


现在让我们来查看该表的状态。


SQL> select * from tab;

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
BIN$04LhcpndanfgMAAAAAANPw==$0 TABLE


表 RECYCLETEST 已不存在,但是请注意出现新表 BIN$04LhcpndanfgMAAAAAANPw==$0。这就是所发生的事情:被删除的表 RECYCLETEST 并没有完全消失,而是重命名为一个由系统定义的名称。它存在于同一个表空间中,具有与原始表相同的结构。如果在该表上定义了索引或触发器,则它们也被重命名,使用与表相同的命名规则。任何相关源(如过程)都失效;原始表的触发器和索引被改为放置在重命名的表 BIN$04LhcpndanfgMAAAAAANPw==$0 上,保持被删除表的完整对象结构。

表及其相关对象被放置在一个称为“回收站”的逻辑容器中,它类似于您 PC 机中的回收站。但是,对象并没有从它们原先所在的表空间中删除;它们仍然占用那里的空间。回收站只是一个列出被删除对象目录的逻辑结构。在 SQL*Plus 提示符处使用以下命令来查看其内容(您需要使用 SQL*Plus 10.1 来进行此操作):


SQL> show recyclebin

ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ ------------------
RECYCLETEST      BIN$04LhcpndanfgMAAAAAANPw==$0 TABLE        2004-02-16:21:13:31


结果显示了表的原始名称 RECYCLETEST,并显示了回收站中的新名称,该名称与我们看到的删除后所创建的新表名称相同。(注意:确切的名称可能因平台不同而不同。)为恢复该表,您所需要做的就是使用 FLASHBACK TABLE 命令:


SQL> FLASHBACK TABLE RECYCLETEST TO BEFORE DROP;

FLASHBACK COMPLETE.

SQL> SELECT * FROM TAB;

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
RECYCLETEST                    TABLE


瞧!表毫不费力地恢复了。如果现在查看回收站,它将是空的。

记住,将表放在回收站里并不在原始表空间中释放空间。要释放空间,您需要使用以下命令清空回收站:


PURGE RECYCLEBIN;


但是如果您希望完全删除该表而不需要使用闪回特性,该怎么办?在这种情况下,可以使用以下命令永久删除该表:

DROP TABLE RECYCLETEST PURGE;


此命令不会将表重命名为回收站中的名称,而是永久删除该表,就象 10g 之前的版本一样。

管理回收站

如果在该过程中没有实际删除表 — 因而没有释放表空间 — 那么当被删除的对象占用了所有空间时,会发生什么事?

答案很简单:这种情况根本不会出现。当表空间被回收站数据完全占满,以至于必须扩展数据文件来容纳更多数据时,可以说表空间处于“空间压力”情况下。此时,对象以先进先出的方式从回收站中自动清除。在删除表之前,相关对象(如索引)被删除。


同样,空间压力可能由特定表空间定义的用户限额而引起。表空间可能有足够的空余空间,但用户可能将其在该表空间中所分配的部分用完了。在这种情况下,Oracle 自动清除该表空间中属于该用户的对象。

此外,有几种方法可以手动控制回收站。如果在删除名为 TEST 的特定表之后需要从回收站中清除它,可以执行

PURGE TABLE TEST;


或者使用其回收站中的名称:

PURGE TABLE "BIN$04LhcpndanfgMAAAAAANPw==$0";


此命令将从回收站中删除表 TEST 及所有相关对象,如索引、约束等,从而节省了空间。但是,如果要从回收站中永久删除索引,则可以使用以下命令来完成工作:

purge index in_test1_01;


此命令将仅仅删除索引,而将表的拷贝留在回收站中。

有时在更高级别上进行清除可能会有用。例如,您可能希望清除表空间 USERS 的回收站中的所有对象。可以执行:

PURGE TABLESPACE USERS;


您也许希望只为该表空间中特定用户清空回收站。在数据仓库类型的环境中,用户创建和删除许多临时表,此时这种方法可能会有用。您可以更改上述命令,限定只清除特定的用户:

PURGE TABLESPACE USERS USER SCOTT;


诸如 SCOTT 等用户可以使用以下命令来清空自己的回收站

PURGE RECYCLEBIN;


DBA 可以使用以下命令清除任何表空间中的所有对象

PURGE DBA_RECYCLEBIN;


可以看到,可以通过多种不同方法来管理回收站,以满足特定的需要。

表版本和闪回功能

用户可能会经常多次创建和删除同一个表,如:

CREATE TABLE TEST (COL1 NUMBER);
INSERT INTO TEST VALUES (1);
commit;
DROP TABLE TEST;
CREATE TABLE TEST (COL1 NUMBER);
INSERT INTO TEST VALUES (2);
commit;
DROP TABLE TEST;
CREATE TABLE TEST (COL1 NUMBER);
INSERT INTO TEST VALUES (3);
commit;
DROP TABLE TEST;


此时,如果您要对表 TEST 执行闪回操作,那么列 COL1 的值应该是什么?常规想法可能认为从回收站取回表的第一个版本,列 COL1 的值是 1。实际上,取回的是表的第三个版本,而不是第一个。因此列 COL1 的值为 3,而不是 1。

此时您还可以取回被删除表的其他版本。但是,表 TEST 的存在不允许出现这种情况。您有两种选择:
使用重命名选项:

FLASHBACK TABLE TEST TO BEFORE DROP RENAME TO TEST2;
FLASHBACK TABLE TEST TO BEFORE DROP RENAME TO TEST1;


这些语句将表的第一个版本恢复到 TEST1,将第二个版本恢复到 TEST2。 TEST1 和 TEST2 中的列 COL1 的值将分别是 1 和 2。或者,
使用表的特定回收站名称进行恢复。为此,首先要识别表的回收站名称,然后执行:

FLASHBACK TABLE "BIN$04LhcpnoanfgMAAAAAANPw==$0" TO BEFORE DROP RENAME TO TEST2;
FLASHBACK TABLE "BIN$04LhcpnqanfgMAAAAAANPw==$0" TO BEFORE DROP RENAME TO TEST1;


这些语句将恢复被删除表的两个版本。

警告……

取消删除特性使表恢复其原始名称,但是索引和触发器等相关对象并没有恢复原始名称,它们仍然使用回收站的名称。在表上定义的源(如视图和过程)没有重新编译,仍然保持无效状态。必须手动得到这些原有名称并应用到闪回表。

信息保留在名为 USER_RECYCLEBIN 的视图中。在对表进行闪回操作前,请使用以下查询来检索原有名称。

SELECT OBJECT_NAME, ORIGINAL_NAME, TYPE
FROM USER_RECYCLEBIN
WHERE BASE_OBJECT = (SELECT BASE_OBJECT FROM USER_RECYCLEBIN
WHERE ORIGINAL_NAME = 'RECYCLETEST')
AND ORIGINAL_NAME != 'RECYCLETEST';

OBJECT_NAME                    ORIGINAL_N TYPE
------------------------------ ---------- --------
BIN$04LhcpnianfgMAAAAAANPw==$0 IN_RT_01   INDEX
BIN$04LhcpnganfgMAAAAAANPw==$0 TR_RT      TRIGGER


在表进行闪回操作后,表 RECYCLETEST 上的索引和触发器将按照 OBJECT_NAME 列中所示进行命名。根据以上查询,可以使用原始名称重新命名对象,如下所示:

ALTER INDEX "BIN$04LhcpnianfgMAAAAAANPw==$0" RENAME TO IN_RT_01;
ALTER TRIGGER "BIN$04LhcpnganfgMAAAAAANPw==$0" RENAME TO TR_RT;


一个值得注意的例外情况是位图索引。当删除位图索引时,它们并不放置在回收站中 — 因此无法检索它们。约束名称也无法从视图中检索。必须从其他来源对它们进行重命名。

闪回表的其他用途

闪回删除表功能不仅限于恢复表的删除操作。与闪回查询类似,您还可以使用它将表恢复到不同的时间点,利用表的“过去”版本来替代整个表。例如,以下语句将表恢复到系统更改号 (SCN) 2202666520。

FLASHBACK TABLE RECYCLETEST TO SCN 2202666520;


此特性使用 Oracle 数据泵技术来创建不同的表,使用闪回功能将该 SCN 处的数据版本填充到表中,然后用新表替代原始表。为找出能够在何种程度上对表进行闪回操作,可以使用 Oracle Database 10g 的版本控制特性。(更多详细信息请参见本系列第 1 周的内容。)在闪回子句中也可以指定时间戳记而不是指定 SCN。

TOP

第 6 周
自动工作负载信息库

学习使用新的特性,这些特性采集数据库性能统计数据和量度,以供分析和调整,并显示在数据库中花费的准确时间,甚至保存会话信息

当您有数据库性能问题时,要解决它您首先要作的是什么?一种常见的方法是看是否存在一种模式:回答诸如“相同的问题是否重复出现?”,“它是否在某个特定的时间段出现?”和“两个问题之间是否有联系?”之类的问题,将几乎总会带来更好的诊断结果。

作为一个数据库管理员,您可能已经投资购买了第三方工具或使用自己开发的工具来在数据库运行期间采集详细的统计数据,并从这些统计数据中导出获得性能量度。在紧急的情况下,您可以访问这些量度来与当前的情况作比较。再度查看这些过去的事件可以给当前的问题带来一些启发,因此不断采集相关的统计数据对于性能分析变得很重要。

一段时间以来,Oracle 在这个领域中的解决方案是它内置的工具 Statspack。虽然某些情况下证明它是非常有价值的,但常常缺少性能故障诊断实践所需的强健性。Oracle Database 10g 提供了一个显著改进的工具:自动工作负载信息库 (AWR)。AWR 和数据库一起安装,不但采集统计数据,还采集导出的量度。


快速测试驱动程序

通过运行 $ORACLE_HOME/rdbms/admin 目录中的 awrrpt.sql 脚本,AWR 的功能可以立即通过它从采集的统计数据和量度中生成的报表得到最好的说明。这个脚本从外观和感觉上类似于 Statspack,它显示所有的现有 AWR 快照并请求两个特定的快照作为时间间隔边界。它产生两种类型的输出:文本格式(类似于 Statspack 报表的文本格式但来自于 AWR 信息库)和默认的 HTML 格式(拥有到部分和子部分的所有超链接),从而提供了非常用户友好的报表。现在运行该脚本以查看报表,从而对 AWR 的功能有一个了解。

实施

现在,让我们来看看 AWR 是如何设计和构建的。AWR 实质上是一个 Oracle 的内置工具,它采集与性能相关的统计数据,并从那些统计数据中导出性能量度,以跟踪潜在的问题。与 Statspack 不同,快照由一个称为 MMON 的新的后台进程及其从进程自动地每小时采集一次。为了节省空间,采集的数据在 7 天后自动清除。快照频率和保留时间都可以由用户修改。要查看当前的设置,您可以使用下面的语句:


select snap_interval, retention
from dba_hist_wr_control;

SNAP_INTERVAL       RETENTION
------------------- -------------------
+00000 01:00:00.0   +00007 00:00:00.0


这些 SQL 语句显示快照每小时采集一次,采集的数据保留 7 天。要修改设置 — 例如,快照时间间隔为 20 分钟,保留时间为两天 — 您可以发出以下命令。参数以分钟为单位。


begin
   dbms_workload_repository.modify_snapshot_settings (
      interval => 20,
      retention => 2*24*60
   );
end;


AWR 使用几个表来存储采集的统计数据,所有的表都存储在新的名称为 SYSAUX 的特定表空间中的 SYS 模式下,并且以 WRM$_* 和 WRH$_* 的格式命名。前一种类型存储元数据信息(如检查的数据库和采集的快照),后一种类型保存实际采集的统计数据。(您可能已经猜到,H 代表“历史数据 (historical)”而 M 代表“元数据 (metadata)”。)在这些表上构建了几种带前缀 DBA_HIST_ 的视图,这些视图可以用来编写您自己的性能诊断工具。视图的名称直接与表相关;例如,视图 DBA_HIST_SYSMETRIC_SUMMARY 是在WRH$_SYSMETRIC_SUMMARY 表上构建的。

AWR 历史表采集的信息比 Statspack 多许多,这些信息包括表空间使用率、文件系统使用率、甚至操作系统统计数据。这些表的完整的列表可以通过以下命令从数据字典中看到:


select view_name from user_views where view_name like 'DBA\_HIST\_%' escape '\';


视图 DBA_HIST_METRIC_NAME 定义 AWR 采集到的重要的量度、它们所属的组和采集它们的单位。例如,下面是一个记录(竖直格式):


DBID                  : 4133493568
GROUP_ID              : 2
GROUP_NAME            : System Metrics Long Duration
METRIC_ID             : 2075
METRIC_NAME           : CPU Usage Per Sec
METRIC_UNIT           : CentiSeconds Per Second


它显示一个量度“每秒 CPU 使用率”以“每秒的厘秒数”为单位进行测量,并且该量度属于一个量度组 “System Metrics Long Duration”。这条记录可以和其它的表(如 DBA_HIST_SYSMETRIC_SUMMARY)结合,以获得数据库的活动信息,形式如下:


select begin_time, intsize, num_interval, minval, maxval, average, standard_deviation sd
from dba_hist_sysmetric_summary where metric_id = 2075;

BEGIN    INTSIZE NUM_INTERVAL   MINVAL  MAXVAL  AVERAGE           SD
----- ---------- ------------   ------- ------- --------  ----------
11:39     179916           30         0      33        3  9.81553548
11:09     180023           30        21      35       28  5.91543912

... and so on ...


下面我们看看 CPU 时间是如何消耗的(以厘秒为单位)。标准差加入到了我们的分析中,它有助于确定平均数字是否反映了实际的工作负载。在第一条记录中,平均值是每秒消耗 CPU 时间 3 厘秒,但标准差是 9.81,这意味着平均值 3 不能反映工作负载。在第二个例子中,平均值为 28,标准差为 5.9,这更具有代表性。这种类型的信息趋势有助于了解几个环境参数对性能量度的影响。

使用统计数据

迄今为止,我们看到了 AWR 所采集的内容,现在让我们看看它将如何处理数据。

大多数性能问题并不是孤立存在的,而留有指示性的迹象,这些迹象将通向问题最终的根源。让我们使用一个典型的调整实践来说明这一点:您注意到系统很慢,于是决定查看等待的原因。您检查发现“缓冲区忙等待”非常高。问题可能出在哪里呢?有几种可能:可能有一个单调增加的索引,可能一个表太满了,以至于要求将单个数据块非常快速地加载到内存中,或其它一些因素。无论在哪种情况下,您都首先要确定存在问题的段。如果它是一个索引段,那么您可以决定重新构建它,把它修改为一个反向键索引,或把它转换成一个在 Oracle Database 10g 中引进的散列分区索引。如果它是一个表,您可以考虑修改存储参数来使它不那么密集,或者利用自动段空间管理把它转移到一个表空间中。

您的处理计划一般是有规律的,并且通常基于您对各种事件的了解和您处理它们的经验。现在设想相同的事情由一个引擎来完成,这个引擎采集量度并根据预先确定的逻辑来推出可能的计划。您的工作不就变得更轻松了吗?

现在在 Oracle Database 10g 中推出的这个引擎称为自动数据库诊断监控程序 (ADDM)。为了作出决策,ADDM 使用了由 AWR 采集的数据。在上面的讨论中,ADDM 可以看到发生了缓冲区忙等待,然后取出相应的数据来查看发生缓冲区忙等待的段,评估其特性和成分,最后为数据库管理员提供解决方案。在 AWR 进行的每一次快照采集之后,调用 ADDM 来检查量度并生成建议。因此,实际上您拥有了一个一天二十四小时工作的自动数据库管理员,它主动地分析数据并生成建议,从而把您解放出来,使您能够关注更具有战略意义的问题。

要查看 ADDM 建议和 AWR 信息库数据,请使用在名称为 DB Home 的页面上的新的 Enterprise Manager 10g 控制台。要查看 AWR 报表,您可以从管理转至工作负载信息库,然后转至 Snapshots 来查看它们。在以后的部分中,我们将更详细地讨论 ADDM。

您还可以指定根据特定的情况来生成警报。这些警报称为服务器生成警报,它们被推送到高级队列中,在其中它们可以被任意监听它的客户端使用。一个这样的客户端是 Enterprise Manager 10g,在其中警报被突出显示。

时间模型

当您有性能问题时,要缩短响应时间您最先想到的是什么?很明显,您希望消除(或减少)增加时间的因素的根源。您如何知道时间花费在哪里 — 不是等待,而是真正在进行工作?

Oracle Database 10g 引进了时间模型,以确定在各个地方花费的时间。花费的总的系统时间记录在视图 V$SYS_TIME_MODEL 中。下面是查询和输出结果。

STAT_NAME                                     VALUE
-------------------------------------         --------------
DB time                                       58211645
DB CPU                                        54500000
background cpu time                           254490000
sequence load elapsed time                    0
parse time elapsed                            1867816
hard parse elapsed time                       1758922
sql execute elapsed time                      57632352
connection management call elapsed time       288819
failed parse elapsed time                     50794
hard parse (sharing criteria) elapsed time    220345
hard parse (bind mismatch) elapsed time       5040
PL/SQL execution elapsed time                 197792
inbound PL/SQL rpc elapsed time               0
PL/SQL compilation elapsed time               593992
Java execution elapsed time                   0
bind/define call elapsed time                 0


注意名称为 DB Time 的统计量,它代表自从例程启动起在数据库中花费的时间。运行示例工作负载,并再次从视图中选中统计值。统计值的差异将代表该工作负载在数据库中花费的时间。在又一个调整回合之后,执行相同的分析,统计值的差异将显示在调整之后 DB Time 的变化,这可以与第一次修改进行比较,以查看调整动作对数据库时间的影响。

除数据库时间之外,V$SYS_TIME_MODEL 视图显示了很多其它的统计量,如在不同类型的分析,甚至在 PL/SQL 编译中花费的时间。

这个视图还显示了总的系统时间,不过您可能对一个更加详细的视图感兴趣:会话级时间。时间统计数据还在会话级进行采集,如视图 V$SESS_TIME_MODEL 中所示,在其中可以看到当前连接的会话(活动和不活动的)的所有统计数据。额外的列 SID 指示显示的统计数据的会话的 SID。

在早期的版本中,这种分析是不可能得到的,用户被迫进行猜测或从各种来源进行分析。在 Oracle Database 10g 中,获得这种信息轻而易举。

活动会话历史

Oracle Database 10g 中的视图 V$SESSION 得到了改善;所有这些改善中最有价值的是包含了等待事件和它们的持续时间,从而不再需要查看视图 V$SESSION_WAIT。不过,因为这个视图只反映实时的值,所以当稍后查看它时,一些重要的信息丢失了。例如,如果您选择从这个视图中检查是否有任何会话在等待任何非空闲的事件,如果有的话,调查这个事件,您可能发现不了任何东西,因为到您选中它的时候等待一定已经结束了。

进入新的特性活动会话历史 (ASH),它类似于 AWR,在一个缓冲区中存储会话性能统计数据,以便稍后进行分析。不过,与 AWR 不同,存储不是永久性地在一个表中进行,而是在内存中进行,并在视图 V$ACTIVE_SESSION_HISTORY 中显示。数据每秒轮询一次,并且只有轮询活动会话。随着时间进行,旧的项目在一个循环缓冲区中被删除,以容纳新的项目,并且这些旧的项目将在视图中显示。要找出有多少个会话在等待某些事件,您可以使用下面的命令

select session_id||','||session_serial# SID, n.name, wait_time, time_waited
from v$active_session_history a, v$event_name n
where n.event# = a.event#


这条命令告诉您事件的名称和等待花费了多少时间。如果您想要深入调查某个特定的等待事件,ASH 的额外的列也将帮助您实现这一目的。例如,如果会话等待的事件之一是缓冲区忙等待,那么正确的诊断必须指出发生等待事件的段。您可以从 ASH 视图列 CURRENT_OBJ# 中获得这一信息,然后该列可以和 DBA_OBJECTS 结合,以获得存在问题的段。

ASH 还记录并行查询服务器会话,这对诊断并行查询等待事件非常有用。如果记录是针对一个并行查询从属进程,那么协调服务器会话的 SID 由 QC_SESSION_ID 列指定。列 SQL_ID 记录产生等待事件的 SQL 语句的 ID,该列可以和 V$SQL 视图结合,以获取存在问题的 SQL 语句。为了方便一个共享用户环境(如 web 应用程序)中的客户端的识别,也显示了 CLIENT_ID 列,这可以由 DBMS_SESSION.SET_IDENTIFIER 来设置。

既然 ASH 信息这么有价值,那么如果以一种类似于 AWR 的永久方式来保存这种信息不是很好吗?幸运的是,它是以这种方式来进行保存的;由 MMON 从进程将信息刷新到 AWR 表中,从而保存在磁盘上,并且信息可以通过视图 DBA_HIST_ACTIVE_SESS_HISTORY 来查看。

人工采集

快照默认是自动采集的,但您也可以按需要采集它们。所有的 AWR 功能都在程序包 DBMS_WORKLOAD_REPOSITORY 中实施。要采集一次快照,只需发出下面的命令:

execute dbms_workload_repository.create_snapshot


它立即采集一次快照,快照被记录在表 WRM$_SNAPSHOT 中。采集的量度是针对 TYPICAL 级别的。如果您想采集更详细的统计数据,您可以在上面的过程中将参数 FLUSH_LEVEL 设置为 ALL。统计数据自动删除,但也可以通过调用过程 drop_snapshot_range() 来手动删除。

基准线

一次典型的性能调整实践从采集量度的基准线集合、作出改动、然后采集另一个基准线集合开始。可以比较这两个集合来检查所作的改动的效果。在 AWR 中,对现有的已采集的快照可以执行相同类型的比较。假定一个名称为 apply_interest 的高度资源密集的进程在下午 1:00 到 3:00 之间运行,对应快照 ID 56 到 59。我们可以为这些快照定义一个名称为 apply_interest_1 的基准线:

exec dbms_workload_repository.create_baseline (56,59,'apply_interest_1')


这一操作将快照从 56 到 59 编号,作为上面指定的基准线的一部分。查看现有的基准线:

select * from dba_hist_baseline;

      DBID BASELINE_ID BASELINE_NAME        START_SNAP_ID END_SNAP_ID
---------- ----------- -------------------- ------------- -----------
4133493568           1 apply_interest_1                56          59


在一些调整步骤之后,我们可以创建另一个基准线 — 假设名称为 apply_interest_2,然后只为那些与这两条基准线相关的快照比较量度。像这样把快照分隔在仅仅几个集合中有助于研究调整对于性能量度的影响。您可以在分析之后使用 drop_baseline() 来删除基准线;快照将保留。此外,当清除例程开始删除旧的快照时,与基准线相关的快照不会被清除,从而允许进行进一步的分析。

结论

这一部分的目的只是介绍 AWR 非常基本的方面。关于更完整的内容,请参见 Oracle Database 10g 文档。此外,关于 AWR 和 ADDM 的一个极好的论述可以在技术白皮书自我管理的数据库:自动性能诊断中找到。在第 15 周,您将了解到关于 ADDM 及使用它来解决实际问题的更多内容。

TOP

第 7 周
SQL*Plus 的成长

随着 Oracle Database 10g的发布,这个小而强大的 DBA 工具有了一些引人注目的变化,包括有用的提示符和高级文件处理

数据库管理员每天用得最多的工具是哪一个?对于许多象我一样在 GUI 革命之前的数据库管理员而言,一定是 SQL*Plus 命令行选件。

虽然随着强大和功能丰富的 Enterprise Manager 10g 的引入,SQL*Plus 在 Oracle Database 10g 中已经发生了一些变化,但这个普遍存在的小工具仍将继续作为 Oracle 原有系统的一部分 — 对初学者和经验丰富的数据库管理员同样适用。

在本部分中,我们将研究对 SQL*Plus 10.1.0.2 所作的一些非常有用的改进。切记,要继续下面的操作,您将需要 Oracle Database 10g 软件的 sqlplus 可执行程序,而不是运行在 10g 数据库上的 Oracle9i Database sqlpuls。


为粗心用户提供的提示符

我在哪里,或我是谁?不,这不是对您精神的拷问;这是关于用户在 SQL*Plus 环境的上下文中位于何处的问题。SQL*Plus 中的默认提示符 — 简单的 SQL> — 不指出用户是谁,以及用户作为什么连接。在早期的版本中,您必须进行一些麻烦的编码来获取变量,但现在不再需要这样了。在 SQL*Plus 10.1.0.2 中,您可以使用:


set sqlprompt "_user _privilege> "


SQL*Plus 提示符显示为


SYS AS SYSDBA>


当然,假定用户 SYS 是作为 SYSDBA 登录的。注意两个预先定义的特殊变量 — _user 和 _privilege — 的使用,它们定义了当前的用户和登录的权限。

让我们再增加一些其它的功能:现在还想显示今天的日期。我们需要做的就是用下面这些命令来使提示符显示想得到的信息。


SQL> set sqlprompt "_user _privilege 'on' _date >"
SYS AS SYSDBA on 06-JAN-04 >


再增加数据库连接标识符怎么样?您想知道您在“什么样”(在生产或开发中)的情况下,这种方法的确非常有帮助。


SQL> set sqlprompt "_user 'on' _date 'at' _connect_identifier >"
ANANDA on 06-JAN-04 at SMILEY >


到目前为止还不错;但我们可能想要以一种更详细的方式来显示当前的日期(带小时和分钟),以更加有用。


ANANDA on 06-JAN-04 at SMILEY > alter session set nls_date_format = 'mm/dd/yyyy hh24:mi:ss';

Session altered.

ANANDA on 01/06/2004 13:03:51 at SMILEY >


问题解决了:输入几行命令就得到了能够提供丰富信息的 SQL 提示符。将它保存在 glogin.sql 文件中,您就始终拥有这些特性。

必须使用引号吗?为什么,不!

在 Oracle9i 中取消了对内部登录的支持之后,全世界许多 DBA 表示反对:他们应当如何在命令行上输入 SYS 的口令并保持安全性?嗯,答案是在操作系统提示符中使用引号:

sqlplus "/ as sysdba"


引号的使用令人遗憾,但还是被大家所接受(虽然有些怨言)。在 Oracle Database 10g 中不需要这样了。现在您可以在 OS 命令提示符下,输入以下命令,不需要引号

sqlplus / as sysdba


作为 SYSDBA 登录。这种改进不仅意味着您少输了两个字符,还有一些额外的好处,例如在 Unix 之类的操作系统中不需要 escape 字符。

改进的文件处理

假设您在处理一个问题,并使用了一些自由格式的即席 SQL 语句。很明显,它们很有用,您想把它们保存起来,以便将来使用。您会怎么做?您就可以把它们保存在各个文件中,如下所示:

select something1 ....
save 1
select something else ....
save 2
select yet another thing ....
save 3


等等。一段时间以后,您需要收集所有保存的文件,以便将来使用。多麻烦!SQL*Plus 10.1.0.2 允许您将语句添加到文件中,进行保存。在前一个例子中,您可以使用:

select something1 ....
save myscripts
select something else ....
save myscripts append
select yet another thing ....
save myscripts append


等等。所有的语句将添加到文件 myscripts.sql 中,从而不再需要保存在单独的文件中,然后把它们连接成单个文件。

这种方法还适用于假脱机。在以前的版本中,命令 SPOOL RESULT.LST 将创建文件 result.lst (如果该文件不存在);但如果该文件已存在,则将覆盖它,而没有提示。这种行为常常(特别在复杂环境下)可能导致不希望的边缘效应,例如重要的输出文件被覆盖。在 10g 中,spool 命令可以使文件内容附加在一个现有的文件后面:

spool result.lst append


如果您想覆盖它,那么该怎么做?简单地省略 append 子句,或使用默认值 REPLACE。以下命令将在写操作之前检查文件是否存在。

spool result.lst create
Use another name or "SPOOL filename[.ext] REPLACE"


这种方法防止覆盖文件 result.lst。

Login.sql 是用于登录的,是吗?

记得文件 login.sql 和 glogin.sql 吗?本来在任何时候当调用 SQL*Plus 时,都将运行当前目录中的 login.sql 文件。但是,有一个严重的局限。在 Oracle9i 和更低版本中,假定在文件中有下面这一行。

set sqlprompt "_connect_identifier >"


当您首先启动 SQL*Plus 与数据库 DB1 连接时,提示符显示:

DB1>


现在,如果您从提示符中与另一个数据库 DB2 连接:

DB1> connect scott/tiger@db2
Connected
DB1>


注意提示符。虽然您现在和 DB2 连接在一起,但提示符仍是 DB1,。很明显,提示符是不正确的。原因很简单:在连接时没有执行 login.sql 文件,只在 SQL*Plus 启动时执行了该文件。后来的连接没有重新执行该文件,使得提示符没有改变。

在 Oracle Database 10g 中,消除了该局限。文件 login.sql 不仅在 SQL*Plus 启动时执行,而且在连接时也执行。因此在 10g 中,如果您当前与数据库 DB1 连接,后来改变了连接,则提示符将改变。

SCOTT at DB1> connect scott/tiger@db2
SCOTT at DB2> connect john/meow@db3
JOHN at DB3>


不希望改变!

如果由于某些原因,您不想使用这些增强的 SQL*Plus,那该怎么办?很简单,用 -c 选项来调用它:

sqlplus -c 9.2


SQL*Plus 环境将和旧的 9.2 版一样运转。

自由地使用 DUAL

您认为有多少开发人员(还有 DBA)经常使用这条命令?

select USER into  from DUAL


可能非常多。对 DUAL 的每次调用创建逻辑 I/O — 数据库没有逻辑 I/O 也可以工作。在某些情况下必须调用 DUAL,如在行 := USER 中。因为 Oracle 代码将 DUAL 当作一个专用的表,所以调整表的某些想法可能不适用或不贴切。

Oracle Database 10g 使得所有这些担心完全消失了:因为 DUAL 是一个专用的表,所以持续获得显著地减少了,并且与从事件 10046 跟踪中看到的优化计划不同。

在 Oracle9i 中
Rows     Execution Plan
-------  ---------------------------------------------------
0  SELECT STATEMENT   GOAL:CHOOSE
1   TABLE ACCESS (FULL) OF 'DUAL'
          

在 10g 中
Rows     Execution Plan
-------  ---------------------------------------------------
0  SELECT STATEMENT   MODE:ALL_ROWS
0   FAST DUAL



注意新的 FAST DUAL 优化计划的使用,与 Oracle9i 中的 DUAL 的 FULL TABLE SCAN 相反。这一改进显著地减少了持续读取,从而为频繁使用 DUAL 表的应用程序带来好处。

注意:从技术角度看,这些 DUAL 改进是在 SQL 优化器中实施的,但是,对许多用户而言,SQL*Plus 是用于处理 SQL 的主要工具。

其它有用的信息

其它的 SQL*Plus 增强在本系列的其它地方进行了说明。例如,我在第 5 周关于闪回表的内容中说明了 RECYCLEBIN 的概念。

与一些流传甚广的传言相反,COPY 命令仍然可用,虽然将在以后的版本中废除。(嗯……,我们不是在 Oracle9i 中就听到这个消息了吗?)如果您有使用这条命令编写的脚本,别沮丧,它不仅可用而且仍被支持。实际上,只错误消息报告方面作了一点改进。如果表有一个 LONG 列,则 COPY 是您创建表的备份的唯一方式,常见的 Create Table As Select 将不能处理带 long 数据类型的列的表。

TOP

第 8 周
自动存储管理

数据库管理员终于可以将自己从单调而常用的增加、移动和删除存储磁盘的任务中解脱出来了 — 并且无需增加额外的成本。

假设您刚得到一个新的 Oracle 数据库的全新的服务器和存储子系统。除操作系统配置之外,在您能够创建数据库之前,最重要的工作是什么?很明显,就是创建存储系统布局 — 或更具体地说,选择一种保护级别,然后构建必需的冗余磁盘阵列 (RAID) 组。

在大多数数据库安装中安装存储器要花费大量的时间。从多种可能中选择一种特定的磁盘配置需要仔细的规划和分析,并且最重要的是,需要详细了解存储技术、卷管理器和文件系统。在这个阶段的设计任务可以大致说明如下(注意这个列表只是代表性的,任务将随配置而变化):

确认存储器在操作系统级通过了认证,并确定冗余保护的级别,该级别可能已经提供(硬件 RAID)。
集中和构建逻辑卷组,并确定分段或镜像是否也是必需的。
在逻辑卷管理器创建的逻辑卷上构建文件系统。
设定所有权和权限,以便 Oracle 进程可以对设备进行打开、读和写操作。
在文件系统上创建数据库,如果可能的话务必在非 RAID 的位置上创建特殊文件,例如重做日志、临时表空间和重做表空间之类的特殊文件。
在大多数公司中,这些步骤大部分是由对存储系统非常了解的某些人来执行的。这里的“某些人”通常不是数据库管理员。

不过,请注意所有这些任务 — 分段、镜像、逻辑文件系统构建 — 的执行都只支持一种类型的服务器,Oracle 数据库。因此,Oracle 自己提供一些技巧来简化或改进这个过程不是很有意义吗?

Oracle Database 10g 正是这么做的。一个新的和激动人心的特性 — 自动存储管理 (ASM) — 使 DBA 能够完全在 Oracle 框架内执行上述的许多任务。利用 ASM,您可以仅利用 Oracle Database 10g 软件自带的功能(无需额外的成本)来将一组磁盘转换成一个高可伸缩的(重点是在“可伸缩”上)和高性能的文件系统/卷管理器。并且您不需要是一个磁盘、卷管理器或文件系统管理方面的专家。

在本部分中,您将了解到关于 ASM 大量的基础知识,以开始在实际的应用程序中使用它。正如您的猜测,这个强大的特性无疑将引发全面的讨论,篇幅所限,我们不能在此作过多介绍,如果您想了解更多的内容,在结论部分列出了一些极好的信息来源。


ASM 是什么?

假设您要在数据库中使用 10 个磁盘。利用 ASM,您不需要在 OS 端创建任何东西,该特性将把一组物理磁盘集合成一个逻辑实体(称为磁盘组)。磁盘组类似于一个分段(和可选镜像)文件系统,但具有重要的差异:它不是一个用于存储用户文件的通用文件系统,并且它不进行缓冲。由于后面的原因,磁盘组提供了直接作为原始设备来访问这个空间,并仍提供文件系统的便利性和灵活性的好处。

逻辑卷管理器一般使用一个函数(如散列函数)来将块的逻辑地址映射到物理块。计算使用 CPU 周期。此外,当增加一个新的磁盘(或 RAID-5 磁盘组)时,这种典型的分段函数需要重新定位整个数据集中的每一位。

相比而言,ASM 使用一个特殊的 Oracle 例程来解决从文件区到物理磁盘块的映射问题。这种设计除了定位文件区非常快速之外,还在增加或删除磁盘时有所帮助,因为文件区的位置不需要调整。这个特殊的 ASM 例程类似于其它的文件系统,必须运行此例程,ASM 才能工作,并且用户不能进行修改。一个 ASM 例程可以在同一台服务器上支持许多 Oracle 数据库例程。

这个特殊的例程只是一个例程,不是用户可以在其中创建对象的数据库。所有关于磁盘的元数据都存储在磁盘组本身中,使得它们能够尽可能地自我描述。

那么概括地说,ASM 的优点是什么?
磁盘增加 — 增加磁盘变得非常容易。无需停机时间,并且文件区域自动重新分配。
I/O 分配 — I/O 自动分布在所有可用的磁盘上,无需人工干预,从而减少了热点出现的可能性。
带区宽度 — 在重做日志文件中分段可以细分(128K,以获得更快的传输速率),对于数据文件,带区则略大一些(1MB,以一次性传输大量的数据块)。
缓冲 — ASM 文件系统不进行缓冲,直接进行输入/输出。
核心化的异步 I/O — 实现核心化的异步 I/O 无需特殊的设置,并且无需使用原始或第三方的文件系统(如 Veritas Quick I/O)。
镜像 — 如果硬件镜像不可用,则可以容易地建立软件镜像。
逐步创建一个基于 ASM 的数据库

下面是如何创建一个基于 ASM 的数据库的具体的示例:

1. 创建一个 ASM 例程

通过指定下列初始化参数,您可以利用数据库创建助手来创建一个 ASM 例程:

INSTANCE_TYPE = ASM


当服务器启动时,您应当启动该例程,而当服务器关闭时,应当最后关闭该例程。

这个参数的默认值是 RDBMS,适用于常见的数据库。

2. 创建磁盘组

在启动 ASM 例程后,利用可用的磁盘创建一个磁盘组。

CREATE DISKGROUP dskgrp1
EXTERNAL REDUNDANCY
DISK
'/dev/d1',
'/dev/d2',
'/dev/d3',
'/dev/d4',
... and so on for all the specific disks ...
;


在上述命令中,我们使数据库利用名称为 /dev/d1、/dev/d2 等的磁盘创建了一个名称为 dksgrp1 的磁盘组。您还可以在 DISK 子句中用通配符指定磁盘名称,而不是分别给定磁盘。

DISK '/dev/d*'


在上述命令中,我们指定了一个子句 EXTERNAL REDUNDANCY,它指示一个磁盘出现故障将使磁盘组停止工作。这通常是由硬件提供冗余(如镜像)的情况。如果没有基于硬件的冗余,则可以设置 ASM 来在磁盘组中创建一组特殊的磁盘(称为 failgroup),以提供这种冗余。

CREATE DISKGROUP dskgrp1
NORMAL REDUNDANCY
FAILGROUP failgrp1 DISK
'/dev/d1',
'/dev/d2',
FAILGROUP failgrp2 DISK
'/dev/d3',
'/dev/d4';


d3 和 d4 不是 d1 和 d2 的镜像,虽然看起来似乎是那样。相反,ASM 使用所有的磁盘来创建一个容错系统。例如,可能利用在 d4 上保留的一个备份来在 d1 中创建磁盘组上的一个文件。另一个文件可以利用 d2 上的备份在 d3 上创建。一个特定的磁盘出现故障,则允许使用另一个磁盘上的备份,以使操作可以继续。例如,您可能丢失了磁盘 d1 和 d2 的控制器,ASM 将为全部故障磁盘组的区块的拷贝建立镜像,以保持数据完整性。

3. 创建表空间

现在利用基于 ASM 的存储器中的一个数据文件来在主数据库中创建一个表空间。

CREATE TABLESPACE USER_DATA DATAFILE '+dskgrp1/user_data_01'
SIZE 1024M
/


就这样!创建过程完成了。

注意磁盘组是如何作为一个虚拟文件系统使用的。这种方法不仅在数据文件中有用,在其它类型的 Oracle 文件中也有用。例如,您可以按以下方式创建在线重做日志文件

LOGFILE GROUP 1 (
'+dskgrp1/redo/group_1.258.3',
'+dskgrp2/redo/group_1.258.3'
) SIZE 50M,
...

****************************************************************
更多的资源
正如之前所提到的,本文的目的不是为了提供关于 AMS 特性的所有知识,使您变成一个专家,原因很简单,相关的信息量太大了。不过,别失望,在 Oracle 技术网上提供了许多的帮助:

“自动存储”(作者:Lannes Morris-Murphy)是关于 ASM 的一篇极好的介绍性文章。

ASMLib — 为 Linux 提供的一个 ASM 特性的资料库 — 扩展了 ASM 功能。本页面还链接了技术参考文献和资料库模块的源代码。


Oracle 数据库管理员指南 10g Release 1 (10.1) 的第 12 章完整说明了 ASM 背后的概念。
***************************************************************
甚至存档日志目标也可以设为一个磁盘组。与 Oracle 数据库相关的全部内容都可以在一个基于 ASM 的磁盘组中创建。例如,备份是 ASM 的另一大用途。您可以设置一组廉价的磁盘来创建一个数据库的恢复区,RMAN 可以使用这个恢复区来创建备份数据库文件和存档日志文件。(在下一个关于 Oracle Database 10g 中的 RMAN 的部分中,您将详细了解如何使用这种功能来为您带来好处。)

请记住,无论 ASM 如何支持仅由 Oracle 数据库创建和读取的文件;它也不能替代一个通用的文件系统,并且不能存储二进制文件和纯文本文件。

维护

让我们看看维护磁盘组所需的一些典型任务。您可能必须经常在磁盘组 dskgrp1 中增加额外的磁盘来适应不断增长的需求。可以执行下面的语句:

alter diskgroup dskgrp1 add disk '/dev/d5';


要查明哪个磁盘在哪个磁盘组中,可以执行下面的语句:

select * from v$asm_disk;


该命令显示了 ASM 例程为所有客户机数据库管理的所有磁盘。在这些磁盘中,您可能决定利用以下命令来删除一个磁盘:

alter diskgroup dskgrp1 drop disk diskb23;


结论

ASM 的引进提供了显著的价值,它使得在 Oracle 数据库中管理文件变得非常容易。利用这个捆绑的特性,您可以从一组磁盘中容易地创建一个高可伸缩和高性能的存储解决方案。任何动态的数据库环境都需要添加、移动和删除磁盘,ASM 提供了必需的工具集,使 DBA 从那些单调的任务中解脱出来。

TOP

第 9 周
RMAN

RMAN 的功能更强大,它具有重新设计的增量备份模式、增量备份的脱机恢复、预览恢复、复原日志进行恢复、文件压缩等功能。

大多数人都认同 RMAN 是用于 Oracle 数据库备份的实际工具。但是与它们所具有的强大功能相比,RMAN 的早期版本并未提供人们所期待的一些功能。就像许多 DBA 一样,如果它没有包含我认为必须具有的功能,我将会异常恼怒。

幸运的是,Oracle 数据库 10g 通过合并人们所想要的许多功能解决了很多这类问题,这使 RMAN 成为一种更强大、更有用的工具。让我们看一下这些功能。


再论增量备份

RMAN 包含一个用于增量备份的选项。但是老实讲,您多久使用一次呢?可能经常用,也可能永远也不会用。

该选项用于指示该工具以相同或较低的级别来备份自上一次增量备份后发生改变的块。例如,在第 1 天采用完全备份 (level_0),而在第 2、3 天采用两个 level_1 的增量。后面的两个备份只是备份了第 1 天和第 2 天之间,及第 2 天和第 3 天之间更改过的块,而不是跨整个备份时间进行备份。这种策略减少了备份规模、需要的空间较少,并缩小了备份窗口,减少了网络间移动的数据量。

执行增量备份的最重要的原因是:与数据仓库环境关联起来,在该环境中许多操作都是在 NOLOGGING 模式下执行的,并且数据更改不会涉及到存档的日志文件—因此,不可能发生介质恢复。考虑到今天的数据仓库的巨大规模,以及其中的大部分数据并没有发生改变的事实,就会知道执行完全备份既不值得又不实际。相反,在 RMAN 中执行增量备份是一个理想的选择。

既然如此,那么为什么许多 DBA 极少执行增量备份呢?一个原因是:在 Oracle 9i 及其较低的版本中,RMAN 会扫描所有的数据块以确定要备份的内容。这个过程给系统施加了如此大的压力,以致于执行增量备份变得不实际。

Oracle 数据库 10g RMAN 以消除了该缺陷的方式来执行增量备份。它使用一个文件,类似于文件系统中的日志,来跟踪自上一次备份起更改过的块。RMAN 读取该文件来确定将要备份的块。

您可以通过发布以下命令来启用该跟踪机制:

SQL> alter database enable block change tracking using file '/rman_bkups/change.log';


该命令将创建一个名为 /rman_bkups/change.log 的二进制文件,以用于跟踪。相反,您可以使用以下命令来禁用跟踪:

SQL> alter database disable block change tracking;


要想查看当前是否启用了对更改的跟踪,您可以查询:

SQL> select filename, status from v$block_change_tracking;


快速恢复区

在 Oracle 9i 中引入的闪回查询,依赖于撤消表空间来闪回到先前的版本,因此限制了它深入到过去的能力。快速恢复通过创建闪回日志提供了一个可选的解决方案,它类似于重做日志,用于将数据库恢复到先前的状态。 总之,您为数据库创建了一个快速恢复区,指定了其大小,并用如下 SQL 命令将数据库置于快速恢复模式下:

alter system set db_recovery_file_dest = '/ora_flash_area';
alter system set db_recovery_file_dest_size = 2g;
alter system set db_flashback_retention_target = 1440;
alter database flashback on;


该数据库必须处于存档日志模式下以支持闪回。此过程在目录 /ora_flash_area 中创建了 Oracle 管理文件,其总大小高达 2GB。对数据库所作的更改将写入到这些文件中,并且可用于将数据库快速恢复到过去的某个点上。

默认情况下,RMAN 还使用 /ora_flash_area 来存储备份文件;因此,RMAN 是存储在磁盘上,而不是磁带上。鉴于此,您就有能力指定您需要备份的天数。在该期限之后,如果需要更多的空间,则会自动将这些文件删除。

快速恢复区不必是一个文件系统或一个目录,但是—,它可以是一个自动存储管理 (ASM) 磁盘组。如果是那样的话,就可以通过如下命令来指定快速恢复区:

alter system set db_recovery_file_dest = '+dskgrp1';


因此,结合使用 ASM 和 RMAN,您就可以使用廉价的磁盘(如 Serial ATA 或 SCSI 驱动)来构建一个高度可伸缩的、容错能力强的存储系统,而不需要额外的软件。(有关 ASM 的详细信息,请参阅本系列中的 第 8 周 的内容。)此过程不但使存储过程更快,也使之能用足够便宜的、基于磁带的方法来完成。

一个额外的好处是防止用户错误。由于 ASM 不是真正的文件系统,使其遭受 DBA 和系统管理员意外破坏的可能性也更小一些。

增量合并

假如您有如下备份计划:

星期天 - 第 0 级(完全),带有标签 level_0
星期一 - 第 1 级(增量),带有标签 level_1_mon
星期二 - 第 1 级(增量),带有标签 level_1_tue

等等。如果数据库在星期天发生故障,在 Oracle 10g 之前的版本中,您将不得不恢复标签 level_0,然后应用所有六个增量。它将持续一段较长的时间,这是许多 DBA 不进行增量备份的另一个原因。

Oracle 数据库 10g RMAN 从根本上改变了此格局。现在,您的增量备份命令看起来如下所示:

RMAN> backup incremental level_1 for recover of copy with tag level_0 database;


在此,我们指示 RMAN 进行 level_1 增量备份,并将其与带有 level_0 标签的完全备份副本合并。在执行该命令之后,level_0 就成为了那一天的完全备份。

因此,在星期二,带有标签 level_0 的备份,当将其与 level_1 增量备份合并时,它就变得与完全的星期二备份相等。同样地,对于星期六采用的增量,当采用磁盘上的备份时,它将会与完全的 level_0 星期六备份相等。如果数据库在星期六发生故障,您只需恢复 level_0 备份外加一小份存档日志,使数据库一致;在此不需要应用额外的增量。该方法显著地削减了恢复时间、加快了备份速度,并消除了再一次执行完全的数据库备份的需要。

压缩文件

对于快速恢复区中基于磁盘的备份,仍有一个大的限制:磁盘空间。特别是当经网络进行时—通常情况下就是这样—那么创建一个尽可能小的备份集是明智的。在 Oracle 数据库 10g RMAN 中,您可以在备份命令内部压缩文件:

RMAN> backup as compressed backupset incremental level 1 database;


注意子句 COMPRESSED 的用法。它将用一个显著不同的方式压缩备份文件:在恢复时,RMAN 不用解压缩就能读取文件。为了确认压缩,检查如下的输出信息:

channel ORA_DISK_1:starting compressed incremental level 1 datafile backupset


此外,您可以通过检查 RMAN 列表输出来验证备份已被压缩:

RMAN> list output;

BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
3       Incr 1  2M         DISK        00:00:00     26-FEB-04      
BP Key:3   Status:AVAILABLE  Compressed:YES  TagAG20040226T100154
Piece Name:/ora_flash_area/SMILEY10/backupset/2004_02_26/o1_mf_ncsn1_TAG20040226T100154_03w2m3lr_.bkp
Controlfile Included:Ckp SCN:318556       Ckp time:26-FEB-04
SPFILE Included:Modification time:26-FEB-04


对于任意的压缩过程,该方法都会对 CPU 产生压力。作为折衷,您可以在磁盘上保存更多的 RMAN 备份,它准备好为还原和恢复操作所用。此外,您可以在物理备用数据库上制作 RMAN 备份,它可用于恢复初始的数据库。该方法将备份源卸载到另一台主机上。

在您开始行动之前先看看:恢复预览

在 Oracle 数据库 10g中,RMAN 通过提供执行恢复操作所需要的预览备份的能力向前迈进了一大步。

RMAN> restore database preview;


列表 1 显示了该操作的输出结果。您还可以预览特定的恢复操作;例如:

restore tablespace users preview;


预览允许您通过执行周期性的、有规则的检查,来确保您的备份基础架构的恢复准备就绪。

Resetlogs 和恢复

假设您丢失了当前的联机重做日志文件,并且您不得不执行一个不完全的数据库恢复—一种很少见但听说过的情况。最大的问题是 resetlogs;在不完全的恢复之后,您必须用 resetlogs 子句打开数据库,它把日志线程的序列号设置为 1,会使您的 RMAN 中的早期备份作废并使恢复操作面临更多的挑战。

在 Oracle 9i 及其较低的版本中,如果您需要将数据库恢复到执行 resetlogs 操作之前的某个版本,您将不得不恢复到一个不同的拷贝。在 Oracle 数据库 10g 中,您不必这样做。由于控制文件中额外的基础架构,在执行 resetlogs 之前或之后,RMAN 现在都可以容易地使用所有备份来恢复 Oracle 数据库。它不需要关闭数据库来制作一个备份。这种新功能意味着在执行 resetlogs 操作之后,可以立即为用户社区重新打开数据库。

为 RMAN 作好准备

Oracle 数据库 10g RMAN 中的增强功能使它成为您的备份策略中的甚至更具强制性的工具。对增量备份过程的改进只会使 RMAN 难以被忽视。

有关 Oracle 10g 中的 RMAN 的更多信息,请参阅 Oracle Database Backup and Recovery Basics 10g 第 1 版 (10.1) 中第 4 章的内容。

TOP

第 10 周
审计告知一切

Oracle 数据库 10g 审计以一种非常详细的级别捕获用户行为,它可以消除手动的、基于触发器的审计

假定用户 Joe 具有更新那张表的权限,并按如下所示的方式更新了表中的一行数据。


update SCOTT.EMP set salary = 12000 where empno = 123456;


您如何在数据库中跟踪这种行为呢?在 Oracle 9i 数据库及其较低版本中,审计只能捕获“谁”执行此操作,而不能捕获执行了“什么”内容。例如,它让您知道 Joe 更新了 SCOTT 所有的表 EMP,但它不会显示他更新了该表中员工号为 123456 的薪水列。它不会显示更改前的薪水列的值—要捕获如此详细的更改,您将不得不编写您自己的触发器来捕获更改前的值,或使用 Log Miner 将它们从存档日志中检索出来。

这两种方法都能让您跟踪更改的内容并记录更改前的值,但其成本非常高。使用触发器编写审计数据可能会对性能产生主要的影响;鉴于此,在某些情况下(如在第三方应用中)禁止使用用户定义的触发器。Log Miner 不会影响性能,但它是依赖于存档日志的可用性来跟踪更改的。

细粒度审计 (FGA),是在 Oracle 9i 中引入的,能够记录 SCN 号和行级的更改以重建旧的数据,但是它们只能用于 select 语句,而不能用于 DML,如 update、insert 和 delete 语句。因此,对于 Oracle 数据库 10g 之前的版本,使用触发器虽然对于以行级跟踪用户初始的更改是没有吸引力的选择,但它也是唯一可靠的方法。

随着 Oracle 10g 的到来,由于审计能力的两个重大的改变,这些限制也随之而去。由于两种审计类型涉及到—标准审计(在所有版本中均可用)和细粒度审计(在 Oracle 9i 及其以上版本中可用)—我们将分别对它们进行处理,然后看看它们是如何相互补充以提供一个单一的、强大的跟踪功能。

新特性

首先,FGA 现在除了支持 select 语句外,还支持 DMA 语句。这些更改都记录在同一个位置,即表 FGA_LOG$ 中,并通过 DBA_FGA_AUDIT_TRAIL 视图显示出来。除了 DML 外,您现在可以选择只有在访问了所有或者甚至很少的相关的列后,才可以触发一个线索。(有关 FGA 在 Oracle 10g 中是如何工作的详细信息,请参阅该主题的我的技术文章的内容。)

标准审计,是由 SQL 命令 AUDIT 执行的,可用于为特定的对象快速、容易地设置跟踪。例如,如果您想跟踪对 Scott 所拥有的表 EMP 的所有更新,您可以发出如下命令:

audit UPDATE on SCOTT.EMP by access;


任何用户每一次更新表 SCOTT.EMP 时,该命令都会把所有的更新记录到审计跟踪表 AUD$ 中,可以通过 DBA_AUDIT_TRAIL 视图来查看。

这个功能对于 Oracle 10g 之前的版本也是可用的。但是,在那些版本中,写到跟踪中的信息仅限于少数相关的项,如:发出该语句的用户、时间、终端标识号等等;它缺少某些重要的信息,如绑定变量的值。在 Oracle 10g 中,除了以前的版本中所收集到的内容之外,审计操作还捕获了许多这些重要的信息片断。用于审计的原始表 AUD$,包含若干个用于记录它们的新列,相应地,DBA_AUDIT_TRAIL 视图也包含这些列。让我们详细地研究一下。

EXTENDED_TIMESTAMP。 该列以 TIMESTAMP (6) 格式记录了审计记录的时间戳,它是用格林尼治标准时间(也称为全球统一时间)来记录时间的,其小数点后的秒数到 9 为止,并且带有时区信息。以这种格式存储的时间的一个例子如下所示。

2004-3-13 18.10.13.123456000 -5:0


日期表示为 2004 年 3 月 13 日,是美国的东部标准时间,它比全球统一时间晚 5 小时(用 -5.0 来表示)。

这种以扩展格式显示的时间有助于把审计跟踪精确定位到一个更窄的时间间隔中,从而增强了它们的用途,特别是在数据库横跨多个时区时更是如此。

GLOBAL_UID 和 PROXY_SESSIONID。 当使用某种身份管理组件如 Oracle Internet Directory 进行身份验证时,用户对数据库的访问权限稍有不同。例如,当将他们访问数据库时,可能将他们视为企业用户。审计这些用户不会在 DBA_AUDIT_TRAIL 视图的 USERNAME 列中记录他们的企业用户标识号,以使该信息无用。在 Oracle 数据库 10g 中,全局(或企业)用户唯一的标识号记录在 GLOBAL_UID 列中,并且没有作进一步的处理或设置。该列可用于查询目录服务器,以查找有关该企业用户的完整的详细信息。

有时企业用户也许是通过一个代理用户连接到数据库,特别是在多层应用中。可以通过命令为用户提供代理身份验证

alter user scott grant connect to appuser;


该命令将允许用户 SCOTT 以 APPUSER 的身份,作为代理用户连接到数据库。在那种情况下,COMMENT_TEXT 列将通过存储值 PROXY 来记录事实;但是对于 Oracle 9i 而言,代理用户的会话标识号将不会进行记录。在 Oracle 10g 中,PROXY_SESSIONID 列记录了它,用于精确标识代理会话。

INSTANCE_NUMBER。 在 Oracle 真正应用集群 (RAC) 环境中,它可能有助于知道在进行更改时用户连接的是哪一个特定的例程。在 Oracle 10g 中,该列记录了例程号,它是由该例程的初始化参数文件指定的。

OS_PROCESS。 在 Oracle 9i 及其较低的版本中,只会在审计跟踪中记录 SID 值;而不会记录操作系统进程标识号。但是,服务器进程的操作系统进程标识号随后可能是必要的,例如,用于交叉引用一个线索文件。在 Oracle 10g 中,该值也记录在该列中。

TRANSACTIONID。 在此就产生了最关键的信息价格。假定用户发出下面的命令

update CLASS set size = 10 where class_id = 123;
commit;


该命令获取一个事务项,并且生成一个审计记录。但是,您怎样知道该审计记录真正记录的是什么内容呢?如果记录是一个事务,该事务标识号就会存储在该列中。您可以使用它把审计跟踪与 FLASHBACK_TRANSACTION_QUERY 视图联接起来。下面是该视图中的列的一个小示例。

select start_scn,  start_timestamp,
commit_scn, commit_timestamp, undo_change#, row_id, undo_sql
from flashback_transaction_query
where xid = '<the transaction id>';


除了记录对该事务所做的通常的统计外,如 undo change#、rowid 等等,Oracle 10g 还可以在 UNDO_SQL 列中记录撤消对事务所作更改 SQL 命令,以及在 ROW_ID 列显示的受影响行的 rowid。

系统更改号。 最终,它记录更改前的值。您怎样执行该操作呢?按 Oracle 9i 中的 FGA 所指出的那样,更改前的值可以通过闪回查询来获取。但是您需要知道该更改的系统更改号 (SCN),它可以在审计跟踪的该列中捕获到。您可以发出下面的命令

select size from class as of SCN 123456
where where class_id = 123;


这将显示用户所看到的内容或更改前的值。

扩展的 DB 审计

记住我们最初的兴趣:为了捕获用户发出的 SQL 语句,以及在标准审计中无法捕获的绑定变量。在 Oracle 数据库 10g 中进入增强型审计,其中这些任务变得如同更改一个简单的初始化参数一样微不足道。只需把下列代码行放入参数文件中。

audit_trail = db_extended


如果使用该参数,该参数将在各列中记录 SQL 文本和绑定变量值。该值在早期的版本中不可用。

触发器何时是必要的

避免误检。 审计跟踪是通过来自于原始事务的自治事务生成的。因此,即使原始事务回滚,它们也会提交。

有一个简单例子演示了这一点。假定我们已在表 CLASS 上为 UPDATE 设置了审计。用户发出一条语句以将数据值从 20 更新为 10,然后将其回滚,如下所示。

update class set size = 10 where class_id = 123;
rollback


现在该列的 SIZE 值将变成 20,而不是 10,好像用户从未做过任何事情。但是,即使回滚,审计跟踪也将捕获该更改。在某些情况下这可能不是人们所想要的,尤其是用户执行了许多回滚时。在这种情况下,您也许不得不使用触发器仅捕获已提交的更改。如果表 CLASS 上有一个触发器用于将记录插入到用户定义的审计线索中,在回滚的基础上审计线索也被回滚。

捕获之前更改的值。 Oracle 提供的审计跟踪不会显示更改前后的值。例如,上述的更改将创建一个审计记录,它显示了语句和更改的 SCN 号,但没有显示更改前的值 (20)。可以使用闪回查询通过 SCN 号获取该值,但是它依赖于在撤消段中可用的信息。如果该信息无法在由 undo_retention 时间段指定的期限内捕获到,就永远不能检索出先前的值来。使用触发器保证了无需依赖于 undo_retention 时间段即可捕获到该值,并且有时很有用。在这两种环境下,您可以决定继续使用触发器以细粒度的级别来记录审计跟踪。

统一的审计跟踪

由于 FGA 和标准审计捕获的是相同类型的信息,当把它们结合起来使用时可以提供许多重要的信息。Oracle 数据库 10g 把这些跟踪合并到一个称为 DBA_COMMON_AUDIT_TRAIL 的通用跟踪中,它是 DBA_AUDIT_TRAIL 视图和 DBA_FGA_AUDIT_TRAIL 视图的一个 UNION ALL 视图。但是,在这两种审计类型之间有一些重大的区别。

结论

在 Oracle 10g 中,审计已经从一个单纯的“操作记录者”成长为一个“事实记录机制”,它能以一个非常详细的级别来捕获用户的行为,这可以消除您对手动的、基于触发器的审计的需要。它还结合了标准审计和 FGA 的跟踪,这使其更易于跟踪数据库访问,而不用考虑它是如何生成的。

有关附加信息,请参阅 Oracle Database Security Guide 10g 第 1 版 (10.1)中的第 11 章的内容。

TOP

第 11 周
等待界面

10g 等待界面为还没有被 ADDM 捕获的即时性能问题提供了有价值的诊断数据

“数据库太慢了!”

这句话通常出自一位严格的用户之口。如果您和我一样,那么在您的 DBA 生涯中您肯定无数次听到过这句话。


那么,您又怎样解决该问题呢?除了对用户置之不理之外(这是我们大多数人都不敢奢望的想法),您可能要做的第一件事就是查看是否有任何会话在等待数据库内部或外部的任何事件。

Oracle 提供了一个简单但一流的机制来达到此目的:V$SESSION_WAIT 视图。该视图显示了有助于您的诊断的各种信息,如一个会话正在等待或已经等待的事件,以及等待了多长时间和多少次。例如,如果会话在等待事件 "b file sequential read",列 P1 和 P2 将显示会话正在等待的块的 file_id 和 block_id。

对于大多数等待事件而言,这个视图足够了,但它还不是一个强健的调整工具,之所以如此说,至少是因为以下两个重要原因:
该视图是当前情况的一个快照。当等待不再存在时,会话先前出现的那些等待的历史也将消失,从而使得事后诊断非常困难。V$SESSION_EVENT 提供了累积的但不是非常详细的数据。
V$SESSION_WAIT 包含了只与等待事件相关的信息;要获得所有其它的相关信息(如用户 ID 和终端),您必须将它和 V$SESSION 视图结合使用。

在 Oracle 数据库 10g 中,等待界面经过了彻底的重新设计,从而只需更少的 DBA 干预即可提供更多的信息。在本文中,我们将浏览这些新的特性,并了解它们如何帮助我们诊断性能问题。对于大多数性能问题,您可以从自动数据库诊断管理器 (ADDM) 中获得扩展分析,但对于还没有被 ADDM 捕获的即时问题,等待界面将提供有价值的诊断数据。

增强的会话等待

第一个增强涉及到 V$SESSION_WAIT 本身。这一点通过示例可以很好地说明。

假定您的用户抱怨会话挂起了。您查明了该会话的 SID,并在 V$SESSION_WAIT 视图中选中了该 SID 的记录。输出显示如下。

SID                      : 269
SEQ#                     : 56
EVENT                    :enqX - row lock contention
P1TEXT                   :name|mode
P1                       : 1415053318
P1RAW                    : 54580006
P2TEXT                   :usn<<16 | slot
P2                       : 327681
P2RAW                    : 00050001
P3TEXT                   :sequence
P3                       : 43
P3RAW                    :0000002B
WAIT_CLASS_ID            : 4217450380
WAIT_CLASS#              : 1
WAIT_CLASS               : Application
WAIT_TIME                : -2
SECONDS_IN_WAIT          : 0
STATE                    :WAITED UNKNOWN TIME


注意以黑体显示的列;在这些列中,WAIT_CLASS_ID、WAIT_CLASS# 和 WAIT_CLASS 是 10g 中新增的列。列 WAIT_CLASS 指示等待的类型,必须将其作为有效的等待事件解决或者作为空闲的等待事件退出。在上面的例子中,等待类显示为 Application,这表示它是一个需要您注意的等待。

该列突出显示那些能够证明与您的调整最相关的少数几条记录。例如,您可以使用如下查询来获取事件的等待会话。

select wait_class, event, sid, state, wait_time, seconds_in_wait
from v$session_wait
order by wait_class, event, sid
/


下面是一个样例输出:

WAIT_CLASS  EVENT                       SID STATE                WAIT_TIME SECONDS_IN_WAIT
----------  -------------------- ---------- ------------------- ---------- ---------------
Application enqX -                   269 WAITING                      0              73
row lock contention        
Idle        Queue Monitor Wait          270 WAITING                      0              40
Idle        SQL*Net message from client 265 WAITING                      0              73
Idle        jobq slave wait             259 WAITING                      0            8485
Idle        pmon timer                  280 WAITING                      0              73
Idle        rdbms ipc message           267 WAITING                      0          184770
Idle        wakeup time manager         268 WAITING                      0              40
Network     SQL*Net message to client   272 WAITED SHORT TIME           -1               0


在这,您可以看到几个事件(如 Queue Monitor Wait 和 JobQueue Slave)被明确地归为 Idle 事件。您可以将它们作为非阻塞等待消除掉;不过,有时这些“空闲”事件可能指示一个内在的问题。例如,与 SQL*Net 相关的事件可能指示高网络延迟(除其他因素外)。

另一件要注意的重要的事情是,WAIT_TIME 的值为 -2。某些平台(如 Windows)不支持快速计时机制。如果在这些平台上没有设定初始化参数 TIMED_STATISTICS,那么将无法获得准确的计时统计数据。在这种情况下,在 Oracle9i 中,该列将显示一个非常大的数字,这使问题变得更加不清晰。在 10g 中,值 -2 指示这种情况 — 平台不支持快速定时机制并且没有设定 TIMED_STATISTICS。(对于本文剩下的部分,我们将假定存在一个快速计时机制。)

会话也显示等待

记得长期以来一直需要将 V$SESSION_WAIT 与 V$SESSION 结合使用以获得有关会话的其他详细信息吗?嗯,这已经成为历史了。在 10g 中,V$SESSION 视图还显示由 V$SESSION_WAIT 显示的等待。下面是 V$SESSION 视图其余的列,这些列显示了会话当前等待的等待事件。

EVENT#                     NUMBER
EVENT                      VARCHAR2(64)
P1TEXT                     VARCHAR2(64)
P1                         NUMBER
P1RAW                      RAW(4)
P2TEXT                     VARCHAR2(64)
P2                         NUMBER
P2RAW                      RAW(4)
P3TEXT                     VARCHAR2(64)
P3                         NUMBER
P3RAW                      RAW(4)
WAIT_CLASS_ID              NUMBER
WAIT_CLASS#                NUMBER
WAIT_CLASS                 VARCHAR2(64)
WAIT_TIME                  NUMBER
SECONDS_IN_WAIT            NUMBER
STATE                      VARCHAR2(19)


这些列与 V$SESSION_WAIT 中的那些列相同,且显示相同的信息,从而不再需要在那个视图中查看它们了。因此,对于等待任意事件的任意会话,您仅需要查看一个视图。

让我们回到原来的问题:SID 为 269 的会话正等待事件 enqX — row lock contention,指示它正等待被另一个会话占用的锁。要诊断该问题,您必须识别占用锁的那个会话。但您如何才能做到这一点?

在 Oracle9i 及更低版本中,您可能得编写复杂(和极耗资源)的查询来获得占用锁的会话的 SID。而在 10g 中,您所要做的就是执行以下查询:

select BLOCKING_SESSION_STATUS, BLOCKING_SESSION
from v$session
where sid = 269

BLOCKING_SE BLOCKING_SESSION
----------- ----------------
VALID                    265


找到了:SID 为 265 的会话阻塞了会话 269。还能更容易吗?

有多少等待?

用户仍然在缠着您,因为用户的问题仍然没有得到满意的解答。为什么用户的会话花了这么长时间才完成?您可以执行以下命令来找出原因:

select * from v$session_wait_class where sid = 269;


输出返回为:

SID SERIAL# WAIT_CLASS_ID WAIT_CLASS# WAIT_CLASS    TOTAL_WAITS TIME_WAITED
---- ------- ------------- ----------- ------------- ----------- -----------
269    1106    4217450380           1 Application           873      261537
269    1106    3290255840           2 Configuration           4           4
269    1106    3386400367           5 Commit                  1           0
269    1106    2723168908           6 Idle                   15      148408
269    1106    2000153315           7 Network                15           0
269    1106    1740759767           8 User I/O               26           1


注意这里有关会话等待的大量信息。现在您知道了,该会话已经为与应用程序相关的等待等待了 873 次(共 261,537 厘秒),在与网络相关的事件中等待了 15 次等等。

以此类推,您可以使用以下查询来查看系统范围的等待类的统计数据。同样,时间是以厘秒为单位的。

select * from v$system_wait_class;

WAIT_CLASS_ID WAIT_CLASS# WAIT_CLASS    TOTAL_WAITS TIME_WAITED
------------- ----------- ------------- ----------- -----------
1893977003           0 Other                2483       18108
4217450380           1 Application          1352      386101
3290255840           2 Configuration          82         230
3875070507           4 Concurrency            80         395
3386400367           5 Commit               2625        1925
2723168908           6 Idle               645527   219397953
2000153315           7 Network              2125           2
1740759767           8 User I/O             5085        3006
4108307767           9 System I/O         127979       18623


大多数问题不是孤立出现的;它们留下了揭示真相的线索,模式可以识别这些线索。可以按如下方式从等待类的一个历史视图中查看模式。

select * from v$waitclassmetric;


这个视图存储了最后一分钟内与等待类相关的统计数据。

select wait_class#, wait_class_id,
average_waiter_count "awc", dbtime_in_wait,
time_waited,  wait_count
from v$waitclassmetric
/

WAIT_CLASS# WAIT_CLASS_ID  AWC DBTIME_IN_WAIT TIME_WAITED WAIT_COUNT
----------- ------------- ---- -------------- ----------- ----------
          0    1893977003    0              0           0          1
          1    4217450380    2             90        1499          5
          2    3290255840    0              0           4          3
          3    4166625743    0              0           0          0
          4    3875070507    0              0           0          1
          5    3386400367    0              0           0          0
          6    2723168908   59              0      351541        264
          7    2000153315    0              0           0         25
          8    1740759767    0              0           0          0
          9    4108307767    0              0           8        100
         10    2396326234    0              0           0          0
         11    3871361733    0              0           0          0


注意 WAIT_CLASS_ID 和相关的统计数据。对于值 4217450380,我们看到 2 个会话在最后一分钟内总共等待了该类 5 次(1,499 厘秒)。但该等待类是什么?您可以从 V$SYSTEM_WAIT_CLASS 中获取这一信息(如上所示)— 就是 Application 类。

注意名称为 DBTIME_IN_WAIT 的列,这是一个非常有用的列。在我们第 6 周关于自动工作负载信息库 (AWR) 的部分中,您可能还记得在 10g 中是以更细粒化的方式来报告时间的,并且可以确定在数据库中花费的准确时间。DBTIME_IN_WAIT 显示在数据库中花费的时间。

一切都留有线索

用户终于离开了,您长舒了一口气。但您可能仍然想寻根究底,希望查明主要是哪些等待造成用户会话中的问题。当然,您可以通过查询 V$SESSION_WAIT 而轻易地得到答案 — 但不幸的是,等待事件现在不存在了,因此该视图没有它们的任何记录。您该怎么办?

在 10g 中,自动保留活动会话最后 10 个事件的会话等待历史。这个历史可通过 V$SESSION_WAIT_HISTORY 视图查看。要找出这些事件,您可以简单地执行:

select event, wait_time, wait_count
from v$session_wait_history
where sid = 265
/

EVENT                           WAIT_TIME WAIT_COUNT
------------------------------ ---------- ----------
log file switch completion              2          1
log file switch completion              1          1
log file switch completion              0          1
SQL*Net message from client         49852          1
SQL*Net message to client               0          1
enq:TX - row lock contention          28          1
SQL*Net message from client           131          1
SQL*Net message to client               0          1
log file sync                           2          1
log buffer space                        1          1


当会话变为非活动状态或断开时,记录从该视图中消失。不过,这些等待的历史保留在 AWR 表中,以便进一步分析。从 AWR 中显示会话等待的视图是 V$ACTIVE_SESSION_HISTORY。(同样,有关 AWR 的更多信息,请参考本系列的第 6 周。)

结论

通过 Oracle 数据库 10g 中的等待模型的增强,分析性能问题变得非常容易。提供的会话等待历史可以帮助您在会话经历等待后诊断问题。将等待归为各种等待类还有助于您了解每种类型等待所造成的影响,这在研究正确的纠正方法时将带来便利。

有关等待事件动态性能视图和等待事件本身的更多信息,请参考《Oracle 数据库性能调整指南 10g 第 1 版 (10.1)》的第 10 章。

TOP

第 12 周
物化视图

利用强制查询重写和新的强大的调整顾问程序 — 它们使您不再需要凭猜测进行工作 — 的引入,在 10g 中管理物化视图变得更加容易

物化视图 (MV) — 也称为快照 — 一段时间来已经广泛使用。MV 在一个段中存储查询结果,并且能够在提交查询时将结果返回给用户,从而不再需要重新执行查询 — 在查询要执行几次时(这在数据仓库环境中非常常见),这是一个很大的好处。物化视图可以利用一个快速刷新机制从基础表中全部或增量刷新。

假定您已经定义了一个物化视图,如下:


create materialized view mv_hotel_resv
refresh fast
enable query rewrite
as
select distinct city, resv_id, cust_name
from hotels h, reservations r
where r.hotel_id = h.hotel_id';


您如何才能知道已经为这个物化视图创建了其正常工作所必需的所有对象?在 Oracle 数据库 10g 之前,这是用 DBMS_MVIEW 程序包中的 EXPLAIN_MVIEW 和 EXPLAIN_REWRITE 过程来判断的。这些过程(在 10g 中仍然提供)非常简要地说明一种特定的功能 — 如快速刷新功能或查询重写功能 — 可能用于上述的物化视图,但不提供如何实现这些功能的建议。相反,需要对每一个物化视图的结构进行目视检查,这是非常不实际的。

在 10g 中,新的 DBMS_ADVISOR 程序包中的一个名为 TUNE_MVIEW 的过程使得这项工作变得非常容易:您利用 IN 参数来调用程序包,这构造了物化视图创建脚本的全部内容。该过程创建一个顾问程序任务 (Advisor Task),它拥有一个特定的名称,仅利用 OUT 参数就能够把这个名称传回给您。

下面是一个例子。因为第一个参数是一个 OUT 参数,所以您需要在 SQL*Plus 中定义一个变量来保存它。

SQL> -- 首先定义一个变量来保存 OUT 参数
SQL> var adv_name varchar2(20)
SQL>  begin
2  dbms_advisor.tune_mview
  3     (
4        :adv_name,
5        'create materialized view mv_hotel_resv refresh fast enable query rewrite as
select distinct city, resv_id, cust_name from hotels h,
            reservations r where r.hotel_id = h.hotel_id');
6* end;


现在您可以在该变量中找出顾问程序的名称。

SQL> print adv_name

ADV_NAME
-----------------------
TASK_117


接下来,通过查询一个新的 DBA_TUNE_MVIEW 来获取由这个顾问程序提供的建议。务必在运行该命令之前执行 SET LONG 999999,因为该视图中的列语句是一个 CLOB,默认情况下只显示 80 个字符。

select script_type, statement
from   dba_tune_mview
where  task_name = 'TASK_117'
order  by script_type, action_id;


下面是输出:

SCRIPT_TYPE    STATEMENT
-------------- ------------------------------------------------------------
IMPLEMENTATION CREATE MATERIALIZED VIEW LOG ON "ARUP"."HOTELS" WITH ROWID,
SEQUENCE ("HOTEL_ID","CITY")  INCLUDING NEW VALUES

IMPLEMENTATION ALTER MATERIALIZED VIEW LOG FORCE ON "ARUP"."HOTELS" ADD
ROWID, SEQUENCE ("HOTEL_ID","CITY")  INCLUDING NEW VALUES

IMPLEMENTATION CREATE MATERIALIZED VIEW LOG ON "ARUP"."RESERVATIONS" WITH
ROWID, SEQUENCE ("RESV_ID","HOTEL_ID","CUST_NAME")
INCLUDING NEW VALUES

IMPLEMENTATION ALTER MATERIALIZED VIEW LOG FORCE ON "ARUP"."RESERVATIONS"
ADD ROWID, SEQUENCE ("RESV_ID","HOTEL_ID","CUST_NAME")
INCLUDING NEW VALUES

IMPLEMENTATION CREATE MATERIALIZED VIEW ARUP.MV_HOTEL_RESV   REFRESH FAST
WITH ROWID ENABLE QUERY REWRITE AS SELECT
ARUP.RESERVATIONS.CUST_NAME C1, ARUP.RESERVATIONS.RESV_ID
C2, ARUP.HOTELS.CITY C3, COUNT(*) M1 FROM ARUP.RESERVATIONS,
ARUP.HOTELS WHERE ARUP.HOTELS.HOTEL_ID =
ARUP.RESERVATIONS.HOTEL_ID GROUP BY
ARUP.RESERVATIONS.CUST_NAME, ARUP.RESERVATIONS.RESV_ID,
ARUP.HOTELS.CITY

UNDO           DROP MATERIALIZED VIEW ARUP.MV_HOTEL_RESV


SCRIPT_TYPE 列显示建议的性质。大多数行将要执行,因此名称为 IMPLEMENTATION。如果接受,则需按照由 ACTION_ID 列指出的特定顺序执行建议的操作。

如果您仔细查看这些自动生成的建议,那么您将注意到它们与您自己通过目视分析生成的建议是类似的。这些建议合乎逻辑;快速刷新的存在需要在拥有适当子句(如那些包含新值的子句)的基础表上有一个 MATERIALIZED VIEW LOG。STATEMENT 列甚至提供了实施这些建议的确切 SQL 语句。

在实施的最后一个步骤中,顾问程序建议改变创建物化视图的方式。注意我们的例子中的不同之处:将一个 count(*) 添加到了物化视图中。因为我们将这个物化视图定义为可快速刷新的,所以必须有 count(*),以便顾问程序纠正遗漏。

TUNE_MVIEW 过程不仅在建议方面超越了在 EXPLAIN_MVIEW 和 EXPLAIN_REWRITE 中提供的功能,还为创建相同的物化视图指出了更容易和更高效的途径。有时,顾问程序可以实际推荐多个物化视图,以使查询更加高效。

您可能会问,如果任何一个经验丰富的 DBA 都能够找出 MV 创建脚本中缺了什么,然后自己纠正它,那这还有什么用?嗯,顾问程序正是用来完成这项工作的:它是一位经验丰富、高度自觉的自动数据库管理员,它可以生成能与人的建议相媲美的建议,但有一个非常重要的不同之处:它免费工作,并且不会要求休假或加薪。这一好处使高级 DBA 解放出来,将日常的工作交给较低级的 DBA,从而允许他们将其专业技能应用到更具有战略意义的目标上。

您还可以将顾问程序的名称作为值传递给 TUNE_MVIEW 过程中的参数,这将使用该名称而非系统生成的名称生成一个的顾问程序。

更容易的实施

既然您可以看到建议,那么您可能想实施它们。一种方式是选择列 STATEMENT,假脱机到一个文件,然后执行该脚本文件。一种更容易的替代方法是调用附带的封装过程:

begin
dbms_advisor.create_file (
dbms_advisor.get_task_script ('TASK_117'),  
'MVTUNE_OUTDIR',
'mvtune_script.sql'
);
end;
/


该过程调用假定您已经定义了一个目录对象,例如:

create directory mvtune_outdir as '/home/oracle/mvtune_outdir';


对 dbms_advisor 的调用将在 /home/oracle/mvtune_outdir 目录中创建一个名为 mvtune_script.sql 的文件。如果您查看一下这个文件,您将看到:

Rem  SQL Access Advisor:Version 10.1.0.1 - Production
Rem
Rem  Username:ARUP
Rem  TaskASK_117
Rem  Execution date:
Rem

set feedback 1
set linesize 80
set trimspool on
set tab off
set pagesize 60

whenever sqlerror CONTINUE

CREATE MATERIALIZED VIEW LOG ON
"ARUP"."HOTELS"
WITH ROWID, SEQUENCE("HOTEL_ID","CITY")
INCLUDING NEW VALUES;

ALTER MATERIALIZED VIEW LOG FORCE ON
"ARUP"."HOTELS"
ADD ROWID, SEQUENCE("HOTEL_ID","CITY")
INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW LOG ON
"ARUP"."RESERVATIONS"
WITH ROWID, SEQUENCE("RESV_ID","HOTEL_ID","CUST_NAME")
INCLUDING NEW VALUES;

ALTER MATERIALIZED VIEW LOG FORCE ON
"ARUP"."RESERVATIONS"
ADD ROWID, SEQUENCE("RESV_ID","HOTEL_ID","CUST_NAME")
INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW ARUP.MV_HOTEL_RESV
REFRESH FAST WITH ROWID
ENABLE QUERY REWRITE
AS SELECT ARUP.RESERVATIONS.CUST_NAME C1, ARUP.RESERVATIONS.RESV_ID C2, ARUP.HOTELS.CITY
C3, COUNT(*) M1 FROM ARUP.RESERVATIONS, ARUP.HOTELS WHERE ARUP.HOTELS.HOTEL_ID
= ARUP.RESERVATIONS.HOTEL_ID GROUP BY ARUP.RESERVATIONS.CUST_NAME, ARUP.RESERVATIONS.RESV_ID,
ARUP.HOTELS.CITY;

whenever sqlerror EXIT SQL.SQLCODE

begin
dbms_advisor.mark_recommendation('TASK_117',1,'IMPLEMENTED');
end;
/


这个文件包含了您实施建议所需的一切,从而为您省去了相当大的手动创建文件的麻烦。这个自动数据库管理员又一次能够为您完成工作。

重写或退出!

至此,您一定意识到了查询重写特性有多重要和多有用。它显著地减少了 I/O 和处理,并能够更快地返回结果。

让我们基于上述例子假定一种情况。用户执行以下查询:

Select city, sum(actual_rate)
from hotels h, reservations r, trans t
where t.resv_id = r.resv_id
and h.hotel_id = r.hotel_id
group by city;


执行状态显示以下内容:

0   recursive calls
0   db block gets
6   consistent gets
0   physical reads
0   redo size
478 bytes sent via SQL*Net to client
496 bytes received via SQL*Net from client
2   SQL*Net roundtrips to/from client
1   sorts (memory)
0   sorts (disk)


注意 consistent gets 的值,它为 6 — 一个非常低的值。这个结果基于的事实是,重写了查询来使用在三个表上创建的两个物化视图。选择不是从表中进行的,而是从物化视图中进行,从而消耗了更少的资源(如 I/O 和 CPU)。

但如果查询重写失败了,那该怎么办?它失败的原因可能有以下几种:如果初始化参数 query_rewrite_integrity 的值被设为 TRUSTED,且 MV 的状态是 STALE,那么将不会重写该查询。您可以通过在查询之前在会话中设定这个值来模拟这个过程。

alter session set query_rewrite_enabled = false;


在这条命令之后,说明计划 (EXPLAIN PLAN) 显示是从所有三个表中而不是从 MV 中作出的选择。执行状态现在显示:

0   recursive calls
0   db block gets
16  consistent gets
0   physical reads
0   redo size
478 bytes sent via SQL*Net to client
496 bytes received via SQL*Net from client
2   SQL*Net roundtrips to/from client
2   sorts (memory)
0   sorts (disk)


注意 consistent gets 的值:它从 6 猛增到了 16。在实际情况下,这个结果可能无法接受,因为无法提供所需的额外资源,因此您可能想自己重写查询。在这种情况下,您可以确保如果而且只有在查询被重写的情况下,才允许进行查询。

在 Oracle9i 数据库和更低版本中,决策是单向的:您可以禁用查询重写,但不能禁用基础表访问。不过 Oracle 数据库 10g 提供了一种机制 — 通过一个特殊的提示 REWRITE_OR_ERROR 来实现这一目的。上述查询将利用该提示写为:

select /*+ REWRITE_OR_ERROR */ city, sum(actual_rate)
from hotels h, reservations r, trans t
where t.resv_id = r.resv_id
and h.hotel_id = r.hotel_id
group by city;


注意现在的错误消息。

from hotels h, reservations r, trans t
     *
ERROR at line 2:
ORA-30393:a query block in the statement did not rewrite


ORA-30393 是一种特殊类型的错误,它表示无法重写语句来使用 MV;因此,语句失败。这种防出错功能将潜在地防止运行时间很长的查询独占系统资源。不过,请注意一个潜在的陷阱:如果 MV 之一(而不是全部)可用于重写查询,那么查询将成功。因此如果能够使用 MV_ACTUAL_SALES 但不能使用 MV_HOTEL_RESV,那么查询将被重写,错误将不会出现。在这种情况下,执行计划将看起来像这样:

Execution Plan
----------------------------------------------------------
0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=6 Bytes=156)
1    0   SORT (GROUP BY) (Cost=11 Card=6 Bytes=156)
2    1     HASH JOIN (Cost=10 Card=80 Bytes=2080)
3    2       MERGE JOIN (Cost=6 Card=80 Bytes=1520)
4    3         TABLE ACCESS (BY INDEX ROWID) OF 'HOTELS' (TABLE) (Cost=2 Card=8 Bytes=104)
5    4           INDEX (FULL SCAN) OF 'PK_HOTELS' (INDEX (UNIQUE)) (Cost=1 Card=8)
6    3         SORT (JOIN) (Cost=4 Card=80 Bytes=480)
7    6           TABLE ACCESS (FULL) OF 'RESERVATIONS' (TABLE) (Cost=3 Card=80 Bytes=480)
8    2       MAT_VIEW REWRITE ACCESS (FULL) OF 'MV_ACTUAL_SALES' (MAT_VIEW REWRITE) (Cost=3 Card=80 Bytes=560)


查询的确使用 MV_ACTUAL_SALES 而不是 MV_HOTEL_RESV;因而,HOTELS 和 RESERVATIONS 表被访问。这种方法(特别是后一个表的全表扫描),无疑将使用更多的资源 — 在设计查询和 MV 时您将注意到这种情况。

虽然您可以始终利用资源管理器来控制资源使用情况,但使用该提示将防止执行查询,即使在调用资源管理器之前。资源管理器根据优化器统计数据估计所需的资源,因此是否存在足够准确的统计数据将影响这个过程。不过,重写或错误特性将停止表访问,而不管统计数据如何。

说明计划更好地进行说明

在上一个例子中,请注意说明计划输出中的行:

MAT_VIEW REWRITE ACCESS (FULL) OF 'MV_ACTUAL_SALES' (MAT_VIEW REWRITE)


这种访问方法 —MAT_VIEW REWRITE— 是新增的;它显示正在访问 MV,而非表或段。该过程立即告诉您表或 MV 是否被使用 — 即使名称没有表明段的本质。

结论

在 10g 中,通过引入强大的新调整顾问程序 — 它们能够告诉您许多有关 MV 的设计的信息,从而使您不再需要凭猜测进行工作,管理 MV 变得更加容易。我尤其喜欢能够生成一个完整的脚本的调整建议,这种脚本可以快速实施,从而显著地节省时间和精力。强制重写或退出查询的能力在决策支持系统中会非常有帮助 — 在这种系统中必须保留资源,并且未重写的查询将不允许在数据库内随意运行。

有关在 10g 中管理物化视图的更多信息,请参考《Oracle 数据库数据仓库指南 10g 第 1 版 (10.1)》中的第 8 章。

TOP

 45 123
发新话题