
在大型的企业应用或企业级的数据库应用中 要处理的数据量通常可以达到几十到几百GB 有的甚至可以到TB级 虽然存储介质和数据处理技术的发展也很快 但是仍然不能满足用户的需求 为了使用户的大量的数据在读写 *** 作和查询中速度更快 Oracle提供了对表和索引进行分区的技术 以改善大型应用系统的性能
使用分区的优点
·增强可用性 如果表的某个分区出现故障 表在其他分区的数据仍然可用
·维护方便 如果表的某个分区出现故障 需要修复数据 只修复该分区即可
·均衡I/O 可以把不同的分区映射到磁盘以平衡I/O 改善整个系统性能
·改善查询性能 对分区对象的查询可以仅搜索自己关心的分区 提高检索速度
Oracle数据库提供对表或索引的分区方法有三种
·范围分区
·Hash分区(散列分区)
·复合分区
下面将以实例的方式分别对这三种分区方法来说明分区表的使用 为了测试方便 我们先建三个表空间
以下为引用的内容
create tablespace dinya_space
datafile /test/demo/oracle/demodata/dinya dnf size M
create tablespace dinya_space
datafile /test/demo/oracle/demodata/dinya dnf size M
create tablespace dinya_space
datafile /test/demo/oracle/demodata/dinya dnf size M
分区表的创建
范围分区
范围分区就是对数据表中的某个值的范围进行分区 根据某个值的范围 决定将该数据存储在哪个分区上 如根据序号分区 根据业务记录的创建日期进行分区等
需求描述 有一个物料交易表 表名 material_transactions 该表将来可能有千万级的数据记录数 要求在建该表的时候使用分区表 这时候我们可以使用序号分区三个区 每个区中预计存储三千万的数据 也可以使用日期分区 如每五年的数据存储在一个分区上
根据交易记录的序号分区建表 以下为引用的内容
SQL> create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date not null
)
partition by range (transaction_id)
(
partition part_ values less than( ) tablespace dinya_space
partition part_ values less than( ) tablespace dinya_space
partition part_ values less than(maxvalue) tablespace dinya_space
);
Table created
建表成功 根据交易的序号 交易ID在三千万以下的记录将存储在第一个表空间dinya_space 中 分区名为:par_ 在三千万到六千万之间的记录存储在第二个表空间
dinya_space 中 分区名为 par_ 而交易ID在六千万以上的记录存储在第三个表空间dinya_space 中 分区名为par_
根据交易日期分区建表
以下为引用的内容
SQL> create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date not null
)
partition by range (transaction_date)
(
partition part_ values less than(to_date( yyyy mm dd ))
tablespace dinya_space
partition part_ values less than(to_date( yyyy mm dd ))
tablespace dinya_space
partition part_ values less than(maxvalue) tablespace dinya_space
);
Table created
这样我们就分别建了以交易序号和交易日期来分区的分区表 每次插入数据的时候 系统将根据指定的字段的值来自动将记录存储到制定的分区(表空间)中
当然 我们还可以根据需求 使用两个字段的范围分布来分区 如partition
by range ( transaction_id transaction_date)
分区条件中的值也做相应的改变 请读者自行测试
Hash分区(散列分区)
散列分区为通过指定分区编号来均匀分布数据的一种分区类型 因为通过在I/O设备上进行散列分区 使得这些分区大小一致 如将物料交易表的数据根据交易ID散列地存放在指定的三个表空间中
以下为引用的内容
SQL> create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date
)
partition by hash(transaction_id)
(
partition part_ tablespace dinya_space
partition part_ tablespace dinya_space
partition part_ tablespace dinya_space
);
Table created
建表成功 此时插入数据 系统将按transaction_id将记录散列地插入三个分区中 这里也就是三个不同的表空间中
复合分区
有时候我们需要根据范围分区后 每个分区内的数据再散列地分布在几个表空间中 这样我们就要使用复合分区 复合分区是先使用范围分区 然后在每个分区内再使用散列分区的一种分区方法 如将物料交易的记录按时间分区 然后每个分区中的数据分三个子分区 将数据散列地存储在三个指定的表空间中
以下为引用的内容
SQL> create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date
)
partition by range(transaction_date)subpartition by hash(transaction_id)
subpartitions store in (dinya_space dinya_space dinya_space )
(
partition part_ values less than(to_date( yyyy mm dd ))
partition part_ values less than(to_date( yyyy mm dd ))
partition part_ values less than(maxvalue)
);
Table created
该例中 先是根据交易日期进行范围分区 然后根据交易的ID将记录散列地存储在三个表空间中
分区表 *** 作
以上了解了三种分区表的建表方法 下面将使用实际的数据并针对按日期的范围分区来测试分区表的数据记录的 *** 作
插入记录
以下为引用的内容
SQL> insert into dinya_test values( BOOKS sysdate);
row created
SQL> insert into dinya_test values( BOOKS sysdate+ );
row created
SQL> insert into dinya_test values( BOOKS to_date( yyyy mm dd ));
row created
SQL> insert into dinya_test values( BOOKS to_date( yyyy mm dd ));
row created
SQL> insert into dinya_test values( BOOKS to_date( yyyy mm dd ));
row created
SQL> insert into dinya_test values( BOOKS to_date( yyyy mm dd ));
row created
SQL> mit;
Commit plete
SQL>
按上面的建表结果 年前的数据将存储在第一个分区part_ 上 而 年到 年的交易数据将存储在第二个分区part_ 上 年以后的记录存储在第三个分区part_ 上
查询分区表记录 以下为引用的内容
SQL> select from dinya_test partition(part_ );
TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE
BOOKS : :
BOOKS : :
SQL>
SQL> select from dinya_test partition(part_ );
TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE
BOOKS
BOOKS
SQL>
SQL> select from dinya_test partition(part_ );
TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE
BOOKS
BOOKS
SQL>
从查询的结果可以看出 插入的数据已经根据交易时间范围存储在不同的分区中 这里是指定了分区的查询 当然也可以不指定分区 直接执行select from dinya_test查询全部记录
在也检索的数据量很大的时候 指定分区会大大提高检索速度
更新分区表的记录
以下为引用的内容
SQL> update dinya_test partition(part_ ) t set em_description= DESK where
t transaction_id= ;
row updated
SQL> mit;
Commit plete
SQL>
这里将第一个分区中的交易ID= 的记录中的item_description字段更新为 DESK 可以看到已经成功更新了一条记录 但是当更新的时候指定了分区 而根据查询的记录不在该分区中时 将不会更新数据 请看下面的例子 以下为引用的内容
SQL> update dinya_test partition(part_ ) t set em_description= DESK where
t transaction_id= ;
rows updated
SQL> mit;
Commit plete
SQL>
指定了在第一个分区中更新记录 但是条件中限制交易ID为 而查询全表 交易ID为 的记录在第三个分区中 这样该条语句将不会更新记录
删除分区表记录
以下为引用的内容
SQL> delete from dinya_test partition(part_ ) t where t transaction_id= ;
row deleted
SQL> mit;
Commit plete
SQL>
上面例子删除了第二个分区part_ 中的交易记录ID为 的一条记录 和更新数据相同 如果指定了分区 而条件中的数据又不在该分区中时 将不会删除任何数据
分区表索引的使用
分区表和一般表一样可以建立索引 分区表可以创建局部索引和全局索引 当分区中出现许多事务并且要保证所有分区中的数据记录的唯一性时采用全局索引
局部索引分区的建立
以下为引用的内容
SQL> create index dinya_idx_t on dinya_test(item_id)
local
(
partition idx_ tablespace dinya_space
partition idx_ tablespace dinya_space
partition idx_ tablespace dinya_space
);
Index created
SQL>
看查询的执行计划 从下面的执行计划可以看出 系统已经使用了索引
以下为引用的内容
SQL> select from dinya_test partition(part_ ) t where em_id= ;
Execution Plan
SELECT STATEMENT Optimizer=CHOOSE (Cost= Card= Bytes= )
TABLE ACCESS (BY LOCAL INDEX ROWID) OF DINYA_TEST (Cost=
Card= Bytes= )
INDEX (RANGE SCAN) OF DINYA_IDX_T (NON UNIQUE) (Cost=
Card= )
Statistics
recursive calls
db block gets
consistent gets
physical reads
redo size
bytes sent via SQLNet to client
bytes received via SQLNet from client
SQLNet roundtrips to/from client
sorts (memory)
sorts (disk)
rows processed
SQL>
全局索引分区的建立
全局索引建立时global 子句允许指定索引的范围值 这个范围值为索引字段的范围值
以下为引用的内容
SQL> create index dinya_idx_t on dinya_test(item_id)
global partition by range(item_id)
(
partition idx_ values less than ( ) tablespace dinya_space
partition idx_ values less than ( ) tablespace dinya_space
partition idx_ values less than (maxvalue) tablespace dinya_space
);
Index created
SQL>
本例中对表的item_id字段建立索引分区 当然也可以不指定索引分区名直接对整个表建立索引 如
以下为引用的内容
SQL> create index dinya_idx_t on dinya_test(item_id);
Index created
SQL>
同样的 对全局索引根据执行计划可以看出索引已经可以使用
以下为引用的内容
SQL> select from dinya_test t where em_id= ;
Execution Plan
SELECT STATEMENT Optimizer=CHOOSE (Cost= Card= Bytes= )
TABLE ACCESS (BY GLOBAL INDEX ROWID) OF DINYA_TEST (Cost
= Card= Bytes= )
INDEX (RANGE SCAN) OF DINYA_IDX_T (NON UNIQUE) (Cost=
Card= )
Statistics
recursive calls
db block gets
consistent gets
physical reads
redo size
bytes sent via SQLNet to client
bytes received via SQLNet from client
SQLNet roundtrips to/from client
sorts (memory)
sorts (disk)
rows processed
SQL>
分区表的维护
了解了分区表的建立 索引的建立 表和索引的使用后 在应用的还要经常对分区进行维护和管理 日常维护和管理的内容包括 增加一个分区 合并一个分区及删除分区等等 下面以范围分区为例说明增加 合并 删除分区的一般 *** 作
增加一个分区:
以下为引用的内容
SQL> alter table dinya_test
add partition part_ values less than(to_date( yyyy mm dd ))
tablespace dinya_spa
ce ;
Table altered
SQL>
增加一个分区的时候 增加的分区的条件必须大于现有分区的最大值 否则系统将提示ORA partition bound must collate higher than that of the last partition 错误
合并一个分区
以下为引用的内容
SQL> alter table dinya_test merge partitions part_ part_ into partition part_ ;
Table altered
SQL>
在本例中将原有的表的part_ 分区和part_ 分区进行了合并 合并后的分区为part_ 如果在合并的时候把合并后的分区定为part_ 的时候 系统将提示ORA cannot reuse lower bound partition as resulting partition 错误
删除分区
以下为引用的内容
SQL> alter table dinya_test drop partition part_ ;
Table altered
SQL>
删除分区表的一个分区后 查询该表的数据时显示 该分区中的数据已全部丢失 所以执行删除分区动作时要慎重 确保先备份数据后再执行 或将分区合并
总结
lishixinzhi/Article/program/Oracle/201311/17329
Step 1
保证原有数据库数据文件在原来的位置
否则需要在mount的情况下用alter database rename datafile给数据文件改名
Step 2
需要的话修改初始化参数文件
路径 : %ORACHE_HOME%//pfile/initora
Step 3
创建windows服务
oradim -delete -sid
oradim -new -sid -pfile <%ORACHE_HOME%//pfile/initora> -startmode m
Step 4
配置监听器
Step 5
使用REGEDIT创建字符串变量ORACLE_SID为数据库的ORACLE_SID
Step 6
启动监听器/数据库
lsnrctl>start
c:>set ORACLE_SID=
sql>startup
id用1,2,3,4,5纯数字的,你怎么会把它定义为varchar类型?
解决步骤:
(1)新建一个表A,表结构和ib_sql 一样,但把id定义为NUMBER类型。
(2)把ib_sql 中的所有数据插入到A中:INSERT INTO A SELECT FROM ib_sql ;
(3)DROP TABLE ib_sql;
(4)把表A改名为ib_sql: ALTER TABLE A RENAME TO ib_sql;
(5)再执行你上面的语句就可以实现排序
1、首先打开plsql,连接上oracle数据库,假设有一张数据库表叫做 tblTest,通过sql查询也可以看出,这里面是有测试数据的。
2、oracle数据库添加列,比如,往测试表 tblTest 添加一个 日期类型的列 UpdateDate,sql语句就可以像下面这样实现,写完SQL之后,选中这一行sql,点击plsql左上角次轮状的图标执行sql语句:alter table TBLTEST add UpdateDate date;
3、执行成功之后,通过 select from TBLTEST ,就能看到新添加的列默认都是空值。
4、oracle数据库删除列,比如,将上一步添加的 UpdateDate 列删除掉,就可以使用下面的sql语句修改表:alter table tbltest drop column updatedate;
5、执行成功后,再次使用 select from TBLTEST ,就能看到 UpdateDate 列已经删除了。
6、oracle数据库修改列属性,比如,将测试表 tblTest 中 INTEGER 类型的 ITEMNUM 列修改为 number 类型,就可以使用下面的SQL语句:alter table tbltest modify ITEMNUM number;
7、在左侧 tbltest 表名上,点击鼠标右键,选择Edit选项,
8、然后在右侧出现的窗口中,点击Columns标签页,就能看到ITEMNUM已经从 INTEGER 改为 number 类型了。
DUAL表的用途
Dual 是 Oracle中的一个实际存在的表 任何用户均可读取 常用在没有目标表的Select语句块中
查看当前连接用户SQL> select user from dual;USER SYSTEM 查看当前日期 时间SQL> select sysdate from dual;SYSDATE SQL> select to_char(sysdate yyyy mm dd hh :mi:ss ) from dual;TO_CHAR(SYSDATE YYYY MM DDHH : : 当作计算器用SQL> select + from dual; + 查看序列值SQL> create sequence aaa increment by start with ;SQL> select aaa nextval from dual;NEXTVAL SQL> select aaa currval from dual;CURRVAL
关于DUAL表的测试与分析
DUAL就是个一行一列的表 如果你往里执行insert delete truncate *** 作 就会导致很多程序出问题 结果也因sqlplus pl/sql dev等工具而异
查看DUAL是什么OBJECT DUAL是属于SYS schema的一个表 然后以PUBLIC SYNONYM的方式供其他数据库USER使用 SQL> select owner object_name object_type from dba_objects where object_name like %DUAL% ;OWNER OBJECT_NAME OBJECT_TYPE SYS DUAL TABLEPUBLIC DUAL SYNONYM 查看表结构 只有一个字段DUMMY 为VARCHAR ( )型SQL> desc dualName Type Nullable Default Comments DUMMY VARCHAR ( ) Y DUAL表的结构 create table SYS DUAL(DUMMY VARCHAR ( ))tablespace SYSTEMpctfree pctused initrans maxtrans storage(initial Knext Kminextents maxextents pctincrease );/
很是困惑 ORACLE为什么要用VARCHAR( )型 用CHAR( )难道不好么?从这样的表结构来看 DUAL表设计的目的就是要尽可能的简单 以减少检索的开销
还有 DUAL表是建立在SYSTEM表空间的 第一是因为DUAL表是SYS这个用户建的 本来默认的表空间就是SYSTEM 第二 把这个可能经常被查询的表和用户表分开来存放 对于系统性能的是有好处的
有了创建了表 创建了同义词还是不够的 DUAL在SYS这个Schema下面 因此用别的用户登录是无法查询这个表的 因此还需要授权
grant select on SYS DUAL to PUBLIC with grant option;
将Select 权限授予公众 接下来看看DUAL表中的数据 事实上 DUAL表中的数据和ORACLE数据库环境有着十分重要的关系(ORACLE不会为此瘫痪 但是不少存储过程以及一些查询将无法被正确执行)
/ 查询行数 在创建数据库之后 DUAL表中便已经 入了一条记录 个人认为 DUMMY字段的值并没有什么关系 重要的是DUAL表中的记录数SQL> select count() from dual;COUNT() SQL> select from dual;DUMMY X 插入数据 再查询记录 只返回一行记录SQL> insert into dual values ( Y ); row created SQL> mit;Commit plete SQL> insert into dual values ( X ); row created SQL> insert into dual values ( Z ); row created SQL> mit;Commit plete SQL> select count() from dual;COUNT() SQL> select from dual;DUMMY X/ 假我们插入一条数据 DUAL表不是返回一行 而是多行记录 那会是什么结果呢?SQL> insert into dual values( Y ); 行 已插入SQL> mit;提交完成SQL> select from dual;DUMMY XYSQL> select sysdate from dual;SYSDATE
这个时候返回的是两条记录 这样同样会引起问题 在通过使用
select sysdate into v_sysdate from dual;
来获取时间或者其他信息的存储过程来说 ORACLE会抛出TOO_MANY_ROWS(ORA )异常 因此 需要保证在DUAL表内有且仅有一条记录 当然 也不能把DUAL表的UPDATE INSERT DELETE权限随意释放出去 这样对于系统是很危险的
/ 把表截掉SQL> truncate table dual;Table truncated SQL> select count() from dual;COUNT() SQL> select from dual;no rows selectedSQL> select sysdate from dual;no rows selected 试着把DUAL表中的数据删除 看看会出现什么结果 SQL> delete from dual; 行 已删除SQL> select from dual;DUMMY SQL> select sysdate from dual;SYSDATE /
我们便取不到系统日期了 因为 sysdate是个函数 作用于每一个数据行 现在没有数据了 自然就不可能取出系统日期 这个对于很多用
select sysdate into v_sysdate from dual;
这种方式取系统时间以及其他信息的存储过程来说是致命的 因为 Oracle会马上抛出一个NO_DATA_FOUND(ORA )的异常 即使异常被捕获 存储过程也将无法正确完成要求的动作
/ 对于DELETE *** 作来说 ORACLE对DUAL表的 *** 作做了一些内部处理 尽量保证DUAL表中只返回一条记录 当然这写内部 *** 作是不可见的 不管表内有多少记录(没有记录除外) ORACLE对于每次DELETE *** 作都只删除了一条数据 SQL> select count() from dual;COUNT() SQL> delete from dual; 行 已删除SQL> mit;提交完成SQL> select count() from dual;COUNT() /附: ORACLE关于DUAL表不同寻常特性的解释There is internalized code that makes this happen Code checks that ensurethat a table scan of SYS DUAL only returns one row Svrmgrl behaviour is incorrect but this is now an obsolete product The base issue you should always remember and keep is: DUAL table should always have ROW Dual is a normal table with one dummy column of varchar ( ) This is basically used from several applications as a pseudo table for getting results from a select statement that use functions like sysdate or otherprebuilt or application functions If DUAL has no rows at all some applications (that use DUAL) may fail with NO_DATA_FOUND exception If DUAL has more than row then applications (that use DUAL) may fail with TOO_MANY_ROWS exception So DUAL should ALWAYS have and only row/
DUAL表可以执行插入 更新 删除 *** 作 还可以执行drop *** 作 但是不要去执行drop表的 *** 作 否则会使系统不能用 数据库起不了 会报Database startup crashes with ORA 错误
如果DUAL表被 不幸 删除后的恢复 用sys用户登陆 创建DUAL表 授予公众SELECT权限(SQL如上述 但不要给UPDATE INSERT DELETE权限)
向DUAL表插入一条记录(仅此一条) insert into dual values( X );提交修改
用sys用户登陆 SQL> create pfile= d:\pfile bak from spfileSQL> shutdown immediate 在d:\pfile bak文件中最后加入一条 replication_dependency_tracking = FALSE 重新启动数据库 SQL> startup pfile= d:\pfile bak SQL> create table sys DUAL ( DUMMY varchar ( ) )pctfree pctused ;SQL> insert into dual values( X );SQL> mit;SQL> Grant select on dual to Public;
授权成功
以上就是关于Oracle数据库分区表 *** 作方法全部的内容,包括:Oracle数据库分区表 *** 作方法、怎么恢复oracle system表空间的数据、oracle数据库单表查询并且按照主键ID排序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)