ORACLE工程师索引与高性能SQL培训资料

Oracle提供了分区技术以支持VLDB(Very Large DataBase)。分区表通过对分区列的判断,把分区列不同的记录,放到不同的分区中。分区完全对应用透明。 
Oracle的分区表可以包括多个分区,每个分区都是一个独立的段(SEGMENT),可以存放到不同的表空间中。查询时可以通过查询表来访问各个分区中的数据,也可以通过在查询时直接指定分区的方法来进行查询。 
分区提供以下优点: 
由于将数据分散到各个分区中,减少了数据损坏的可能性; 
可以对单独的分区进行备份和恢复; 
可以将分区映射到不同的物理磁盘上,来分散IO; 
提高可管理性、可用性和性能。 
Oracle提供了以下几种分区类型: 
范围分区(range); 
哈希分区(hash); 
列表分区(list); 
范围-哈希复合分区(range-hash); 
范围-列表复合分区(range-list)。 
Oracle的普通表没有办法通过修改属性的方式直接转化为分区表,必须通过重建的方式进行转变,下面介绍三种效率比较高的方法,并说明它们各自的特点。 
方法一:利用原表重建分区表。 
步骤: 
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE); 
表已创建。 
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS; 
已创建6264行。 
SQL> COMMIT; 
提交完成。rt
SQL> CREATE TABLE T_NEW (ID, TIME) PARTITION BY RANGE (TIME) 
  2  (PARTITION P1 VALUES LESS THAN (TO_DATE('2004-7-1', 'YYYY-MM-DD')), 
  3  PARTITION P2 VALUES LESS THAN (TO_DATE('2005-1-1', 'YYYY-MM-DD')), 
  4  PARTITION P3 VALUES LESS THAN (TO_DATE('2005-7-1', 'YYYY-MM-DD')), 
  5  PARTITION P4 VALUES LESS THAN (MAXVALUE))
  6  AS SELECT ID, TIME FROM T; 
表已创建。 
SQL> RENAME T TO T_OLD; 
表已重命名。 
SQL> RENAME T_NEW TO T; 
表已重命名。 
SQL> SELECT COUNT(*) FROM T; 
  COUNT(*)
----------
      6264 
SQL> SELECT COUNT(*) FROM T PARTITION (P1); 
  COUNT(*)
----------
         0 
SQL> SELECT COUNT(*) FROM T PARTITION (P2); 
  COUNT(*)
----------
      6246 
SQL> SELECT COUNT(*) FROM T PARTITION (P3); 
  COUNT(*)
----------
        18 
优点:方法简单易用,由于采用DDL语句,不会产生UNDO,且只产生少量REDO,效率相对较高,而且建表完成后数据已经在分布到各个分区中了。 
不足:对于数据的一致性方面还需要额外的考虑。由于几乎没有办法通过手工锁定T表的方式保证一致性,在执行CREATE TABLE语句和RENAME T_NEW TO T语句直接的修改可能会丢失,如果要保证一致性,需要在执行完语句后对数据进行检查,而这个代价是比较大的。另外在执行两个RENAME语句之间执行的对T的访问会失败。 
适用于修改不频繁的表,在闲时进行操作,表的数据量不宜太大。 
方法二:使用交换分区的方法。 
步骤: 
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE); 
表已创建。 
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS; 
已创建6264行。 
SQL> COMMIT; 
提交完成。 
SQL> CREATE TABLE T_NEW (ID NUMBER PRIMARY KEY, TIME DATE) PARTITION BY RANGE (TIME) 
  (PARTITION P1 VALUES LESS THAN (TO_DATE('2005-7-1', 'YYYY-MM-DD')), 
    PARTITION P2 VALUES LESS THAN (MAXVALUE)); 
表已创建。 
SQL> ALTER TABLE T_NEW EXCHANGE PARTITION P1 WITH TABLE T; 
表已更改。 
SQL> RENAME T TO T_OLD; 
表已重命名。 
SQL> RENAME T_NEW TO T; 
表已重命名。 
SQL> SELECT COUNT(*) FROM T; 
  COUNT(*)
----------
      6264 
优点:只是对数据字典中分区和表的定义进行了修改,没有数据的修改或复制,效率最高。如果对数据在分区中的分布没有进一步要求的话,实现比较简单。
在执行完RENAME操作后,可以检查T_OLD中是否存在数据,如果存在的话,直接将这些数据插入到T中,可以保证对T插入的操作不会丢失。 
不足:仍然存在一致性问题,交换分区之后RENAME T_NEW TO T之前,查询、更新和删除会出现错误或访问不到数据。如果要求数据分布到多个分区中,
则需要进行分区的SPLIT操作,会增加操作的复杂度,效率也会降低。 
适用于包含大数据量的表转到分区表中的一个分区的操作。应尽量在闲时进行操作。 
split partition:
在oracle中,将一个非分区表转换为分区表 (对split partition 和exchange partition使用)
SQL>  create table t_new (id integer,name varchar2(20))
  2   partition by range(id)
  3  ( partition p1 values less than (1001),
  4    partition p2 values less than (maxvalue));
表已创建。
SQL> alter table t_new exchange partition p1 with table t;
表已更改。
SQL> alter table t_new split partition p1 at(301) into (partition p3,partition p1);
表已更改。
SQL> alter table t_new split partition p1 at(601) into (partition p4,partition p1);
表已更改。
SQL> alter table t_new split partition p1 at(1001)into (partition p5,partition p1);
alter table t_new split partition p1 at(1001)into (partition p5,partition p1)
                                  *
第 1 行出现错误:
ORA-14080: 无法按指定的上限来分割分区
SQL> alter table t_new split partition p1 at(1000)into (partition p5,partition p1);
表已更改。
SQL> select count(*) from t_new partition (p1);
  COUNT(*)
----------
         1
SQL> select * from t_new partition (p1);
        ID NAME
---------- --------------------
      1000 abc
SQL> select count(*) from t_new partition(p3);
  COUNT(*)
----------
       300
SQL> select count(*) from t_new partition(p4);
  COUNT(*)
----------
       300
SQL> select count(*) from t_new partition(p1);
  COUNT(*)
----------
         1
SQL> select count(*) from t_new partition(p2);
  COUNT(*)
----------
         0
SQL> select count(*) from t_new partition(p5);
  COUNT(*)
----------
       399
方法三:Oracle9i以上版本,利用在线重定义功能 
步骤: 
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, TIME DATE); 
表已创建。 
SQL> INSERT INTO T SELECT ROWNUM, CREATED FROM DBA_OBJECTS; 
已创建6264行。 
SQL> COMMIT; 
提交完成。 
SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(USER, 'T', DBMS_REDEFINITION.CONS_USE_PK); 
PL/SQL 过程已成功完成。 
SQL> CREATE TABLE T_NEW (ID NUMBER PRIMARY KEY, TIME DATE) PARTITION BY RANGE (TIME) 
  2  (PARTITION P1 VALUES LESS THAN (TO_DATE('2004-7-1', 'YYYY-MM-DD')), 
  3  PARTITION P2 VALUES LESS THAN (TO_DATE('2005-1-1', 'YYYY-MM-DD')), 
  4  PARTITION P3 VALUES LESS THAN (TO_DATE('2005-7-1', 'YYYY-MM-DD')), 
  5  PARTITION P4 VALUES LESS THAN (MAXVALUE)); 
表已创建。 
SQL> EXEC DBMS_REDEFINITION.START_REDEF_TABLE(USER, 'T', 'T_NEW', -
> 'ID ID, TIME TIME', DBMS_REDEFINITION.CONS_USE_PK); 
PL/SQL 过程已成功完成。 
SQL> EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('YANGTK', 'T', 'T_NEW'); 
PL/SQL 过程已成功完成。 
SQL> SELECT COUNT(*) FROM T; 
  COUNT(*)
----------
      6264 
SQL> SELECT COUNT(*) FROM T PARTITION (P2); 
  COUNT(*)
----------
      6246 
SQL> SELECT COUNT(*) FROM T PARTITION (P3); 
  COUNT(*)
----------
        18 
优点:保证数据的一致性,在大部分时间内,表T都可以正常进行DML操作。只在切换的瞬间锁表,具有很高的可用性。这种方法具有很强的灵活性,
对各种不同的需要都能满足。而且,可以在切换前进行相应的授权并建立各种约束,可以做到切换完成后不再需要任何额外的管理操作。 
不足:实现上比上面两种略显复杂。 
适用于各种情况。 
这里只给出了在线重定义表的一个最简单的例子,详细的描述和例子可以参考下面两篇文章。 
Oracle的在线重定义表功能:http://blog.itpub.net/post/468/12855 
Oracle的在线重定义表功能(二):http://blog.itpub.net/post/468/12962 
索引也可以进行分区,分区索引有两种类型:global和local。对于local索引,每一个表分区对应一个索引分区,当表的分区发生变化时,索引的维护由Oracle自动进行。
对于global索引,可以选择是否分区,而且索引的分区可以不与表分区相对应。当对分区进行维护操作时,通常会导致全局索引的INVALDED,必须在执行完操作后REBUILD。
Oracle9i提供了UPDATE GLOBAL INDEXES语句,可以使在进行分区维护的同时重建全局索引。 
全局索引可以包含多个分区的值 局部索引比全局索引容易管理,而全局索引比较快
注意:不能为散列分区 或者 子分区创建全局索引
Oracle的分区功能十分强大。不过用起来发现有两点不大方便: 
第一是已经存在的表没有方法可以直接转化为分区表。不过Oracle提供了在线重定义表的功能,可以通过这种方式来完成普通表到分区表的转化。
可以参考这个例子:http://blog.itpub.net/post/468/13091 
第二点是如果采用了local分区索引,那么在增加表分区的时候,索引分区的表空间是不可控制的。
如果希望将表和索引的分区分开到不同的表空间且不同索引分区也分散到不同的表空间中,那么只能在增加分区后,对新增的分区索引单独rebuild。
Oracle最大允许存在多少个分区呢?
我们可以从Oracle的Concepts手册上找到这个信息,对于Oracle9iR2:
Tables can be partitioned into up to 64,000 separate partitions.
对于Oracle10gR2,Oracle增强了分区特性:
Tables can be partitioned into up to 1024K-1 separate partitions. 
关于何时应该进行分区,Oracle有如下建议:
■ Tables greater than 2GB should always be considered for partitioning. 
■ Tables containing historical data, in which new data is added into the newest partition. 
   A typical example is a historical table where only the current month's data is updatable 
   and the other 11 months are read only.
 create table p_tab1
 ( id integer not null,
    shijian date )
 partition by range (shijian)
 ( partition p1 values less than (to_date('2007-03-01','yyyy-mm-dd')),
   partition p2 values less than (to_date('2007-04-01','yyyy-mm-dd')),
   partition p3 values less than (to_date('2007-07-01','yyyy-mm-dd')),
   partition p4 values less than (to_date('2007-12-01','yyyy-mm-dd')) );
SQL> conn / as sysdba
已连接。
SQL> select tablespace_name from dba_tablespaces;
TABLESPACE_NAME
------------------------------
SYSTEM
UNDOTBS1
SYSAUX
TEMP
USERS
SQL> select name from v$datafile;
NAME
--------------------------------------------------------------------------------
D:\ORACLE\PRODUCT\10.2.0\ORADATA\ERIC\SYSTEM01.DBF
D:\ORACLE\PRODUCT\10.2.0\ORADATA\ERIC\UNDOTBS01.DBF
D:\ORACLE\PRODUCT\10.2.0\ORADATA\ERIC\SYSAUX01.DBF
D:\ORACLE\PRODUCT\10.2.0\ORADATA\ERIC\USERS01.DBF
SQL> create tablespace ERIC
  2  datafile 'D:\ORACLE\PRODUCT\10.2.0\ORADATA\ERIC\eric01.dbf' size 20M;
表空间已创建。
SQL> create user ericlu/eric identified by eric
  2  default tablespace eric01
  3  temporary tablespace temp;
用户已创建。
SQL> grant dba to ericlu;
授权成功。
SQL> disconn
从 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options 断开
SQL> conn ericlu/eric
已连接。
SQL> create table test(
 id integer not null,
 name varchar2(10) ) tablespace eric;
表已创建。
SQL> insert into test values(0,'aa');
已创建 1 行。
SQL> insert into test values(1,'aa');
已创建 1 行。
SQL> insert into test values(2,'aa');
已创建 1 行。
SQL> insert into test values(3,'aa');
已创建 1 行。
SQL> insert into test values(4,'aa');
已创建 1 行。
SQL> insert into test values(5,'aa');
已创建 1 行。
SQL> insert into test values(6,'aa');
已创建 1 行。
SQL> insert into test values(7,'aa');
已创建 1 行。
SQL> insert into test values(8,'aa');
已创建 1 行。
SQL> insert into test values(9,'aa');
已创建 1 行。
SQL> insert into test values(10,'aa');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select table_name,tablespace_name,PARTITIONED from user_tables;
TABLE_NAME                     TABLESPACE_NAME                PAR
------------------------------ ------------------------------ ---
TEST                           ERIC                           NO
SQL> drop table test;
表已删除。
SQL> create tablespace ericlu
  datafile 'D:\oracle\product\10.2.0\oradata\eric\ericlu01.dbf' size 10M;
表空间已创建。
SQL> create table test(
   id integer not null,
   name varchar2(10) )
   partition by range(id)
   ( partition p1 values less than (5) tablespace eric,
    partition p2 values less than (11) tablespace ericlu );
表已创建.
SQL> select * from test partition (p1);
未选定行
SQL> select * from test partition (p2);
未选定行
SQL> select * from test partition (p2);
        ID NAME
---------- ----------
         5 aa
         6 aa
         7 aa
         8 aa
         9 aa
        10 aa
已选择6行。
SQL> select * from test partition (p1);
        ID NAME
---------- ----------
         0 aa
         1 aa
         2 aa
         3 aa
         4 aa
SQL> select table_name,tablespace_name,PARTITIONED from user_tables;
TABLE_NAME                     TABLESPACE_NAME                PAR
------------------------------ ------------------------------ ---
TEST                                                          YES
D:\Documents and Settings\ericlu>exp ericlu/eric owner=ericlu file=1.dmp log=1
og rows=y
Export: Release 10.2.0.1.0 - Production on 星期一 6月 16 16:59:46 2008
Copyright (c) 1982, 2005, Oracle.  All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
即将导出指定的用户...
. 正在导出 pre-schema 过程对象和操作
. 正在导出用户 ERICLU 的外部函数库名
. 导出 PUBLIC 类型同义词
. 正在导出专用类型同义词
. 正在导出用户 ERICLU 的对象类型定义
即将导出 ERICLU 的对象...
. 正在导出数据库链接
. 正在导出序号
. 正在导出簇定义
. 即将导出 ERICLU 的表通过常规路径...
. . 正在导出表                            TEST导出了          11 行
. 正在导出同义词
. 正在导出视图
. 正在导出存储过程
. 正在导出运算符
. 正在导出引用完整性约束条件
. 正在导出触发器
. 正在导出索引类型
. 正在导出位图, 功能性索引和可扩展索引
. 正在导出后期表活动
. 正在导出实体化视图
. 正在导出快照日志
. 正在导出作业队列
. 正在导出刷新组和子组
. 正在导出维
. 正在导出 post-schema 过程对象和操作
. 正在导出统计信息
成功终止导出, 没有出现警告。
D:\Documents and Settings\ericlu>imp ericlu/eric fromuser=ericlu touser=ericlu
ile=1.dmp log=1.log rows=y ignore=y
Import: Release 10.2.0.1.0 - Production on 星期一 6月 16 17:12:49 2008
Copyright (c) 1982, 2005, Oracle.  All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V10.02.01 创建的导出文件
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. . 正在导入表                          "TEST"导入了          11 行
成功终止导入, 没有出现警告。
 begin
for i in 1..100 loop
  insert into tab_2 select * from dba_objects;
   commit;
   end loop;
   end;
 /
SQL> create table tab_3
  2  partition by range(object_id)
  3  (partition p1 values less than(10000),
  4   partition p2 values less than(20000),
  5  partition p3 values less than(30000),
  6  partition p4 values less than(40000),
  7  partition p5 values less than(maxvalue))
  8    as select * from tab_2  ;
表已创建。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值