分区更改跟踪不需要.docx
- 文档编号:6266088
- 上传时间:2023-01-05
- 格式:DOCX
- 页数:13
- 大小:34.17KB
分区更改跟踪不需要.docx
《分区更改跟踪不需要.docx》由会员分享,可在线阅读,更多相关《分区更改跟踪不需要.docx(13页珍藏版)》请在冰豆网上搜索。
分区更改跟踪不需要
分区更改跟踪:
不需要MV日志
要了解此增强功能,首先必须了解物化视图(MV)刷新过程中的分区修整概念。
假设基于列ACC_MGR_ID对表ACCOUNTS进行了分区,每个ACC_MGR_ID值一个分区。
您根据ACCOUNTS创建了一个名为ACC_VIEW的MV,该MV也根据列ACC_MGR_ID进行了分区,每个ACC_MGR_ID一个分区,如下图所示:
假设已经更新了表ACCOUNTS中的记录,但只在分区P1中进行了此更新。
要快速刷新此MV,您只需刷新分区P1而非整个表,这里正是与ACC_MGR_ID相关的数据所在的分区。
Oracle自动执行此任务,通过一个名为分区更改跟踪(PCT)的特性跟踪对分区的更改。
但有一个问题需稍加注意:
要在快速刷新的过程中启用PCT,必须创建MV日志,当表中的行发生变化会填充这些日志。
发出刷新命令后,刷新进程将读取MV日志以识别这些更改。
不用说,该要求增加了操作的总执行时间。
此外,附加的插入操作将消耗CPU周期和I/O带宽。
幸好,在Oracle数据库10g第2版中,PCT不需要MV日志即可工作。
让我们看一看它的作用方式。
首先,确认表ACCOUNTS中没有MV日志。
SQL>select*
2 fromdba_mview_logs
3 wheremaster='ACCOUNTS';
norowsselected
现在,更新该表中的某个记录。
updateaccountssetlast_name='...'
whereacc_mgr_id=3;
该记录位于分区P3中。
现在,您就可以刷新此MV了。
但首先记录表ACCOUNTS所有段的段级统计信息。
稍后,您将使用这些统计信息了解使用了哪些段。
selectSUBOBJECT_NAME,valuefromv$segment_statistics
whereowner='ARUP'
andOBJECT_NAME='ACCOUNTS'
andSTATISTIC_NAME='logicalreads'
orderbySUBOBJECT_NAME
/
SUBOBJECT_NAME VALUE
----------------------------------------
P1 8320
P10 8624
P2 12112
P3 11856
P4 8800
P5 7904
P6 8256
P7 8016
P8 8272
P9 7840
PMAX 256
11rowsselected.
使用快速刷新刷新物化视图ACC_VIEW。
executedbms_mview.refresh('ACC_VIEW','F')
'F'参数指示快速刷新。
但如果表没有MV日志,它是否可以起作用?
刷新完成后,再次检查表ACCOUNTS的段统计信息。
结果如下所示:
SUBOBJECT_NAME VALUE
----------------------------------------
P1 8320
P10 8624
P2 12112
P3 14656
P4 8800
P5 7904
P6 8256
P7 8016
P8 8272
P9 7840
PMAX 256
这些段统计信息显示了在一个逻辑读取过程中选择的段。
由于这些统计信息是累积的,因此您必须查看值(而非绝对值)中的更改。
如果仔细查看以上值,您便会发现只有分区P3的值发生了变化。
因此,在刷新过程中只选择了分区P3而非整个表,确认PCT能否在表即使没有MV日志的情况下工作。
即使在基表没有MV日志的情况下也可以快速刷新MV的能力是一个强大而有用的特性,从而允许您可以在已分区的MV中执行快速刷新而不会增加性能开销。
我认为,该特性是Oracle数据库10g第2版中最有用的数据仓库增强功能
使用多个MV进行查询重写
Oracle8i中引入的查询重写特性在数据仓库开发人员和DBA中轰动一时。
从本质上而言,它将用户查询重写为从MV而非表中进行选择以利用现成的摘要。
例如,请考虑以下一家大型连锁酒店的数据库中的三个表。
SQL>DESCHOTELS
Name Null?
Type
--------------------------------------------------------------
HOTEL_ID NOTNULLNUMBER(10)
CITY VARCHAR2(20)
STATE CHAR
(2)
MANAGER_NAME VARCHAR2(20)
RATE_CLASS CHAR
(2)
SQL>DESCRESERVATIONS
Name Null?
Type
--------------------------------------------------------------
RESV_ID NOTNULLNUMBER(10)
HOTEL_ID NUMBER(10)
CUST_NAME VARCHAR2(20)
START_DATE DATE
END_DATE DATE
RATE NUMBER(10)
SQL>DESCTRANS
Name Null?
Type
--------------------------------------------------------------
TRANS_ID NOTNULLNUMBER(10)
RESV_ID NOTNULLNUMBER(10)
TRANS_DATE DATE
ACTUAL_RATE NUMBER(10)
表HOTELS保存酒店的相关信息。
当顾客预订酒店时,将在表RESERVATIONS(包含房间价格报价)中创建一个记录。
当顾客在酒店结帐时,将在另一个表TRANS中记录现金交易。
但在结帐前,酒店可能决定根据订房情况、升级、优惠等因素向顾客提供不同的房价。
因此,最终的房价可能与预订时的报价不同,而且可以每天都各不相同。
为正确记录这些价格变化,表TRANS有一行专门用来保存每天的房价信息。
为缩短查询响应时间,您可能决定根据用户发出的不同查询构建MV,如:
creatematerializedviewmv_hotel_resv
refreshcomplete
enablequeryrewrite
as
selectcity,resv_id,cust_name
fromhotelsh,reservationsr
wherer.hotel_id=h.hotel_id;
和
creatematerializedviewmv_actual_sales
refreshcomplete
enablequeryrewrite
as
selectresv_id,sum(actual_rate)fromtransgroupbyresv_id;
因此,如果设置了某些参数(如query_rewrite_enabled=true),则类似如下所示的查询
selectcity,cust_name
fromhotelsh,reservationsr
wherer.hotel_id=h.hotel_id;
将重写为
selectcity,cust_name
frommv_hotel_resv;
您可以通过运行该查询并启用自动跟踪来确认MV。
SQL>setautottraceonlyexplain
SQL>selectcity,cust_name
2>fromhotelsh,reservationsr
3>wherer.hotel_id=h.hotel_id;
ExecutionPlan
----------------------------------------------------------
0 SELECTSTATEMENTOptimizer=ALL_ROWS(Cost=3Card=80Bytes=2480)
1 0 MAT_VIEWACCESS(FULL)OF'MV_HOTEL_RESV'(MAT_VIEW)(Cost=3Card=80Bytes=2480)
注意,查询是如何从物化视图MV_HOTEL_RESV而非表HOTELS和RESERVATIONS中进行选择的。
这正是您所需要的。
同样,当您编写一个查询来汇总每个预订编号的实际价格时,将使用物化视图MV_ACTUAL_SALES而非表TRANS。
我们来采用一个不同的查询。
如果要查明每个城市的实际销售额,则将发出
selectcity,sum(actual_rate)
fromhotelsh,reservationsr,transt
wheret.resv_id=r.resv_id
andr.hotel_id=h.hotel_id
groupbycity;
注意此查询结构:
从MV_ACTUAL_SALES中,您可以获得RESV_ID和预订的总销售额。
从MV_HOTEL_RESV中,您可以获得CITY和RESV_ID。
您能将这两个MV连接在一起吗?
当然可以,但在Oracle数据库10g第2版之前,查询重写机制只使用两个MV中的一个(而非两个)自动重写用户查询。
以下是Oracle9i数据库中的执行计划输出。
您可以看到,只使用了MV_HOTEL_RESV和TRANS的整表扫描。
ExecutionPlan
----------------------------------------------------------
0 SELECTSTATEMENTOptimizer=ALL_ROWS(Cost=8Card=6Bytes=120)
1 0 SORT(GROUPBY)(Cost=8Card=6Bytes=120)
2 1 HASHJOIN(Cost=7Card=516Bytes=10320)
3 2 MAT_VIEWREWRITEACCESS(FULL)OF'MV_HOTEL_RESV'(MAT_VIEWREWRITE)
(Cost=3Card=80Bytes=1040)
4 2 TABLEACCESS(FULL)OF'TRANS'(TABLE)
(Cost=3Card=516Bytes=3612)
即使MV可用,该方法也将生成一个非最优的执行计划。
唯一的救济就是创建另一个将所有三个表连接在一起的MV。
但该方法将导致MV的增多,从而大大增加刷新MV所需的时间。
Oracle数据库10g第2版解决了此问题。
现在,以上查询将重写为使用两个MV,如执行计划中所示。
ExecutionPlan
----------------------------------------------------------
0 SELECTSTATEMENTOptimizer=ALL_ROWS(Cost=8Card=6Bytes=120)
1 0 SORT(GROUPBY)(Cost=8Card=6Bytes=120)
2 1 HASHJOIN(Cost=7Card=80Bytes=1600)
3 2 MAT_VIEWREWRITEACCESS(FULL)OF'MV_ACTUAL_SALES'(MAT_VIEWREWRITE)
(Cost=3Card=80Bytes=560)
4 2 MAT_VIEWREWRITEACCESS(FULL)OF'MV_HOTEL_RESV'(MAT_VIEWREWRITE)
(Cost=3Card=80Bytes=1040)
注意,该执行计划是如何只使用了MV而未使用任何其他基表的。
该增强功能在数据仓库中具有显著的优点,这是因为您不必为每个可能的查询创建和刷新MV。
相反,你可以在关键地方创建几个没有太多连接和聚合的MV,Oracle将使用它们来重写查询。
通过备份实现可传输表空间
Oracle8i中引入的可传输表空间为实现更快的跨数据库数据传输提供了迫切需要的支持。
使用此特性,您可以只导出表空间的元数据、传输数据文件并将转储文件导出到目标数据库主机以及导入元数据以将表空间“插入”到目标数据库中。
该表空间中的数据在目标数据库中随即可用。
该方法解决了数据仓库中曾一度存在的一个很棘手的问题:
快速、高效地跨数据库移动数据。
但在OLTP数据库中,该条件通常是不可能存在的,因此传输表空间也是不可能的。
如果OLTP数据库是数据仓库的数据源,则您可能始终无法使用可传输表空间加载它。
在Oracle数据库10g第2版中,可以传输表空间并从另一个数据源(即备份)中插入它。
例如,如果要传输表空间ACCDATA,则可以发出RMAN命令
RMAN>transporttablespaceaccdata
2>TABLESPACEDESTINATION='/home/oracle'
3>auxiliarydestination='/home/oracle';
该命令在位置/home/oracle中创建一个辅助实例,并从其中的备份恢复文件。
此辅助实例的名称是随机生成的。
创建实例后,该过程将基于目录创建一个目录对象,并恢复表空间ACCDATA(我们正在传输的表空间)的文件-所有操作均自动完成,您不必发出任何命令!
目录/home/oracle将包含表空间ACCDATA的所有数据文件、表空间元数据的转储文件以及脚本impscrpt.sql(最重要的)。
该脚本包含将此表空间插入目标表空间所必需的所有命令。
该表空间并非由impdp命令进行传输,而是通过对dbms_streams_tablespace_adm.attach_tablespaces程序包的调用进行传输。
可以在该脚本中找到所有必要的命令。
您可能会问,如果出现错误该怎么办?
这种情况下,可以轻松地进行诊断。
首先,该辅助实例在$ORACLE_HOME/rdbms/log中创建警报日志文件,以便您可以检查该日志以查明潜在的问题。
其次,在提供RMAN命令时,您可以通过发出RMAN命令(该命令将所有输出置于文件tts.log中)将命令和输出重定向到日志文件
rmantarget=/log=tts.log
然后,您便可以检查该文件来查明故障的确切原因。
最后,将把这些文件恢复到/home/oracle的TSPITR__目录中。
例如,如果主数据库的SID为ACCT,RMAN创建的辅助实例的SID为KYED,则目录名为TSPITR_ACCT_KYED。
该目录还包含两个其他子目录:
datafile(用于数据文件)和onlinelog(用于重做日志)。
在完成新表空间的创建之前,可以查看该目录以了解恢复了哪些文件。
(这些文件在该过程结束时会被删除。
)
长期以来,DBA一直期待着能够通过RMAN备份创建一个可传输的表空间。
但请注意,您是从备份(而不是从联机表空间)中插入传输的表空间。
因此,它将不是最新的。
对已分区的按索引组织的表实现快速的分区分割
考虑这样一种情况:
假设您拥有一个已分区的表。
月末到了,但您忘了为下一个月定义分区。
您现在有哪些选择呢?
您唯一的救济方法就是将最大值分区分割为两个部分:
一个用于新月份的分区和一个新的最大值分区。
但将该方法用于已分区的按索引组织的表时将遇到一个小问题。
这种情况下,将先创建物理分区,并将行从最大值分区移动到该分区,这样将消耗I/O和CPU周期。
在Oracle数据库10g第2版中,该过程得到显著简化。
如下图所示,假设您将分区一直定义到5月份,然后已经将PMAX分区定义为一个通用分区。
由于6月份没有特定分区,因此6月份数据进入PMAX分区。
灰显的方框显示了填充到该段中的数据。
由于只填充了部分PMAX分区,因此您只看到一部分灰色区域。
现在,在6月30日对分区PMAX进行分割,以创建6月分区和新的PMAX分区。
由于当前PMAX中的所有数据都将进入新的6月分区,因此Oracle数据库10g第2版只创建新的最大值分区,并使现有分区成为新创建的月分区。
这就导致了根本不会发生数据移动(因此没有“空”的I/O和CPU周期)。
而最好之处在于,ROWID不会发生变化。
通过联机重新定义将LONG转换为LOB
如果数据仓库数据库已经存在一段时间,并且您要处理大型文本数据,则您可能拥有大量数据类型为LONG的列。
毋庸质疑,LONG数据类型在大多数数据操作环境(如通过SUBSTR进行搜索)中是没有用处的。
您肯定需要将它们转换为LOB列。
可以使用DBMS_REDEFINITION程序包联机执行该操作。
但在Oracle数据库10g第2之前,有一个很大的限制。
将LONG列转换为LOB列时,您很希望获得高性能;您需要使该过程尽可能地快。
如果将表进行了分区,则该过程将跨分区并行执行。
但如果未将表进行分区,则该过程将串行执行,从而可能持续很长时间。
幸好,在Oracle数据库10g第2版中,即使表未分区也可以在DBMS_REDEFINITION程序包内部执行从LONG到LOB的联机转换。
我们通过一个示例来了解该转换的过程。
以下是一个用于保存发送给客户的电子邮件的表。
由于邮件正文(存储在MESG_TEXT中)通常是较长的文本数据,因此已将该列定义为LONG。
SQL>descacc_mesg
Name Null?
Type
----------------------------------------------------------
ACC_NO NOTNULLNUMBER
MESG_DT NOTNULLDATE
MESG_TEXT LONG
您需要将该列转换为CLOB。
首先,创建一个结构相同的(最后一列除外,它被定义为CLOB)空临时表。
createtableACC_MESG_INT
(
acc_nonumber,
mesg_dt date,
mesg_textclob
);
现在,启动重新定义过程。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 分区 更改 跟踪 不需要