oracle 11G新特性3Word格式.docx
《oracle 11G新特性3Word格式.docx》由会员分享,可在线阅读,更多相关《oracle 11G新特性3Word格式.docx(17页珍藏版)》请在冰豆网上搜索。
)
partitionbylist(product_code)
subpartitionbylist(state_code)
partitionp101values(101)
(
subpartitionp101_ctvalues('
CT'
),
subpartitionp101_nyvalues('
NY'
subpartitionp101_defvalues(default)
),
partitionp201values(201)
subpartitionp201_ctvalues('
subpartitionp201_nyvalues('
subpartitionp201_defvalues(default)
)
选择并不仅限于此处显示的方法。
您还可以创建列表-范围组合分区。
在上面的示例中,假设产品代码不是离散的,而是在一个范围内。
您将希望根据state_code进行列表分区,然后再根据product_code划分子分区。
下面是实现该操作的代码示例。
createtablesales1
partitionbylist(state_code)
subpartitionbyrange(product_code)
partitionCTvalues('
subpartitionct_100valueslessthan(101),
subpartitionct_200valueslessthan(201)
partitionNYvalues('
subpartitionNY_100valueslessthan(101),
subpartitionNY_200valueslessthan(201)
您也可以创建范围-范围组合分区,如果您有两个日期域,该方法将非常方便。
例如,考虑一个用于销售处理系统的表,该表包括一个交易日期和一个交货日期。
您可能希望根据一个日期进行范围分区,然后再根据另一个日期进行子范围分区。
该方案允许您根据日期进行备份、存档和清除。
总而言之,您在OracleDatabase11g中可以创建以下类型的组合分区:
▪范围-范围
▪范围-散列
▪范围-列表
▪列表-范围
▪列表-散列
▪列表-列表
引用分区
下面是设计分区方案过程中的一个典型问题:
并非所有表都具有您需要根据其进行分区的列。
假设您要创建一个销售系统,该系统包括两个简单的表(sales和customers):
createtablecustomers
cust_idnumberprimarykey,
cust_namevarchar2(200),
ratingvarchar2
(1)notnull
partitionbylist(rating)
partitionpAvalues('
A'
partitionpBvalues('
B'
);
sales表的创建如下所示。
它是customers表的一个子表。
sales_idnumberprimarykey,
cust_idnumbernotnull,
sales_amtnumber,
constraintfk_sales_01
foreignkey(cust_id)
referencescustomers
理想情况下,您希望用相同的方式对sales表和customers表分区:
根据rating列进行列表分区。
但有一个严重问题:
sales表没有名为rating的列!
那么如何根据一个不存在的列进行分区呢?
在OracleDatabase11g中,您可以使用一个称为引用分区的新特性。
下面的示例显示了如何将该特性应用于sales表:
partitionbyreference(fk_sales_01);
这段代码创建了与父表customers中相同的分区。
注意,虽然没有名为rating的列,但仍根据该列对表进行了分区。
partitionbyreference(fk_sales_01)子句包括了分区定义中的外键名。
该语句指示OracleDatabase11g确认通过父表(在该示例中为customers)中使用的方案进行了分区。
注意cust_id列的NOTNULL约束;
这是引用分区所必需的。
如果您检查sales表中分区的分区边界:
SQL>
selectpartition_name,high_value
2fromuser_tab_partitions
3wheretable_name='
SALES'
;
PARTITION_NAMEHIGH_VALUE
----------------------------------------------
PA
PB
高值为空,这意味着此处的边界派生自父表。
分区的名称与父表中的名称相同。
您可以通过查询user_part_tables视图来检查分区的类型。
一个名为ref_ptn_constraint_name的特殊列显示了外键约束名称。
selecttable_name,partitioning_type,ref_ptn_constraint_name
2fromuser_part_tables
3wheretable_namein('
CUSTOMERS'
'
TABLE_NAMEPARTITIONREF_PTN_CONSTRAINT_NAME
-----------------------------------------------------------------
CUSTOMERSLIST
SALESREFERENCEFK_SALES_01
如果您希望按照父表分区的方式对子表进行分区,但没有相同的列,您又不想仅仅为了分区而引入这些列,此时引用分区将非常方便。
而且,您不必针对每个子表显式声明一个很长的分区子句。
间隔分区
范围分区允许您根据分区键列的值的范围创建分区。
下面是一个按范围分区的表的示例:
createtablesales6
sales_dtdate
partitionbyrange(sales_dt)
partitionp0701valueslessthan(to_date('
2007-02-01'
yyyy-mm-dd'
)),
partitionp0702valueslessthan(to_date('
2007-03-01'
))
您在此处仅针对2007年1月和2007年2月定义了分区,如果表中插入一条sales_dt在2007年3月的记录,会发生什么情况?
插入将失败,并显示以下错误:
ORA-14400:
insertedpartitionkeydoesnotmaptoanypartition
显然,您需要针对2007年3月添加一个分区,然后才能插入一条记录。
但通常说起来容易做起来难。
您通常无法容忍事先创建大量分区,但其中很少一部分可能会产生此错误。
如果Oracle以某种方式自动察觉到对新分区的需要,然后创建它们,这样不是更好吗?
OracleDatabase11g可以,它可以使用一个称为间隔分区的特性。
此时,您不必定义分区及它们的边界,只需定义一个定义了每个分区边界的间隔。
下面是使用间隔分区的示例:
interval(numtoyminterval(1,'
MONTH'
注意子句:
interval后面跟着时间间隔。
您在此处指示Oracle为每个月份创建一个时间间隔。
您已经为2007年1月的数据创建了名为p0701的初始分区。
现在,假设您插入了一条包括2007年6月数据的记录:
insertintosales6values(1,'
01-jun-07'
1rowcreated.
Oracle不会返回错误,而是成功执行该语句。
那么这条记录将转向何处?
p0701分区不能包括该记录,我们没有为2007年6月定义分区。
但此时,如果您检查该表的分区:
SALES6'
-------------------------------------------------------------------------------
P0701TO_DATE('
2007-02-0100:
00:
00'
'
SYYYY-MM-DDHH24:
MI:
SS'
NLS_C
ALENDAR=GREGORIA
SYS_P41TO_DATE('
2007-07-0100:
注意名为SYS_P1、高值为2007年7月1日的分区,它最多可以容纳到6月底的数据。
该分区是由Oracle动态创建的,并具有一个系统生成的名称。
现在,假设您输入一个小于最高值的值,如2007年5月1日。
理想情况下,它应该具有自己的分区,因为您的分区时间间隔是一个月。
01-may-07'
SYS_P42TO_DATE('
2007-06-0100:
注意新分区SYS_P42,其上限为6月1日,因此该分区可以保留2006年5月的数据。
该分区是通过拆分SYS_P41分区创建的(针对6月份)。
因此,当您定义一个间隔分区方案时,Oracle会自动创建和维护分区。
如果您希望将分区存储在特定表空间中,可以使用storein子句执行该操作:
storein(TS1,TS2,TS3)
该子句以循环方式将分区存储在表空间TS1、TS2和TS3中。
应用程序开发人员如何定位特定分区?
一种方法是知道名称,这种方法可能不可行,即使您知道名称,这种方法也非常容易出错。
为了便于访问特定分区,OracleDatabase11g为分区SQL提供了一个新语法:
select*fromsales6partitionfor(to_date('
15-may-2007'
dd-mon-yyyy'
));
SALES_IDSALES_DT
-------------------
101-MAY-07
注意新子句for(值),它允许您直接引用分区,而不必通过它们的确切名称进行显式调用。
如果您希望截断或删除一个分区,可以调用这个扩展的分段语法。
以此方式创建表之后,DBA_PART_TABLES视图中的PARTITIONING_TYPE列会显示时间间隔。
系统分区
尽管Oracle对此特性的实际用途期望很少,但我还是希望至少描述一下此特性,因为它真的很酷。
下面是一个很少见但并非不可能发生的用例:
假设您有一个无法用任何逻辑方法分区的表。
结果将是一个巨大的、单一的表,这会导致需要扩展的索引维护和其他操作等问题。
因此,开发人员提出一个解决方案:
他们承诺,如果该表不能以某种方式分区,他们可以通过一种智能方式写入分区。
这样,应用程序就可以控制特定记录进入哪个分区。
DBA只需定义分区。
示例如下:
createtablesales3
sales_id
number,
state_code
number
partitionbysystem
partitionp1tablespaceusers,
partitionp2tablespaceusers
注意,没有任何分区键或边界。
因此,以物理方式将表分成两个段,但仍然是一个逻辑表。
以这种方式定义之后,数据库会为该表创建两个段,而不是只有一个单一的表。
您可以通过以下语句对其进行检查:
selectpartition_name
2fromuser_segments
3wheresegment_name='
SALES3'
PARTITION_NAME
------------------------------
P1
P2
创建本地索引时,也是以相同的方式对其进行分区。
createindexin_sales3_stateonsales3(state_code)local;
Indexcreated.
IN_SALES3_STATE'
可以通过检查user_part_tables来检查分区的类型:
selectpartitioning_type
PARTITION
---------
SYSTEM
这显示为SYSTEM,当然,指示系统分区。
需要注意的一点是,这些表类型的high_value列值为空。
-----------------------------------
P1
下面是一个有趣的问题:
如果没有分区键或方案(如范围、列表或散列),Oracle如何知道传入的记录应进入哪个分区?
答案是:
Oracle不知道。
下面的示例显示了如果您向表中插入一条记录时将发生的情况:
insertintosales3values(1,101,1);
insertintosales3values(1,101,1)
*
ERRORatline1:
ORA-14701:
partition-extendednameorbindvariablemustbeusedforDMLson
tablespartitionedbytheSystemmethod
分区边界是未知的,因此应用程序必须在插入数据的同时使用分区敏感语法来提供该信息。
您需要将该语句重新编写为:
insertintosales3partition(p1)values(1,101,1);
删除时,您不必提供分区敏感语法,但是记住,没有分区边界的概念。
因此,当您发出如下语句时:
deletesales3wherestate_code=1;
Oracle必须扫描所有分区,以查看该行所在的位置。
为了避免出现这种情况,您应将其重新编写为:
deletesales3partition(p1)wherestate_code=1;
更新也是一样的。
这限制了搜索该记录的分区范围。
如果一个表不能以任何逻辑方式进行分区,那么系统分区将提供惊人的优势。
它们使您能够利用分区的优势,同时允许开发人员自由决定记录将进入哪个分区。
单个分区的表空间传输
在OracleDatabase的早期版本中,您能够传输表空间,并且稍后能将其插入不同数据库或同一个数据库中。
该过程涉及复制数据文件,因此它是跨数据库传输数据的最快方法。
然而直到现在,您仍然无法传输单个分区的表空间,然后再将其插回数据库中。
在OracleDatabase11g中,您可以这么做。
假设您有一个名为SALES5的表,它包括了几个名为CT、NY等的分区。
selectpartition_name,tablespace_name
2
fromuser_tab_partitions
3
wheretable_name='
SALES5'
PARTITION_NAMETABLESPACE_NAME
-----------------------------
CT
TS1
NY
TS2
现在,您可以使用如下命令传输CT分区:
$expdptables=scott.sales5:
cttransportable=alwaysdirectory=data_pump_dirdumpfile=p_ct.dmp
Export:
Release11.1.0.4.0-BetaonSunday,10June,200716:
05:
40Copyright(c)2003,2005,Oracle.
Allrightsreserved.Username:
/assysdba
Connectedto:
OracleDatabase11gEnterpriseEditionRelease11.1.0.4.0-Beta
WiththePartitioning,OracleLabelSecurity,OLAP,DataMining
andOracleDatabaseVaultoptions
Starting"
SYS"
."
SYS_EXPORT_TABLE_01"
:
/********ASSYSDBA
tables=scott.sales5:
cttransport