分享
 
 
 

Expert One-on-One Oracle阅读笔记

王朝oracle·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

Expert

One-on-One Oracle阅读笔记

第 6

章 数据库表

6.1 表的类型

1. 堆组织表

2. 索引组织表

3. 聚簇表

4. 散列聚簇表

5. 嵌套表

6. 临时表

7. 对象表

一张表最多有1000列;表的行数理论上没有限制;表上索引个数可以是列的全排列数,而且一次性能够使用32个;表的数量没有限制。

6.2 术语

高水位标记 High Water Mark

曾经包含数据的最右边的块。在全表扫描时,Oracle将扫描高水标记一下的所有块,即使它们不含数据。TRUNCATE将重新设置高水标记。

自由列表

Freelist

在Oracle中用来跟踪高水标记以下有空闲空间的块对象。保留在高水标记以上的块,只有Freelist为空时才能被用到。

并行更新数据时,配置多个Freelist能提高整体性能,代价是增加了存储空间。

PCTFREE和PCTUSED

INITIAL, NEXT和PCTINCREASE

建议使用Local

Managed表空间并设置Extents大小相等。而在没有使用Local

Managed表空间的情况下,建议总是设置INITIAL=NEXT和PCTINCREASE=0,以模拟Local

Managed表空间的使用。

MINEXTENTS和MAXEXTENTS

LOGGING和NOLOGGING

INITRANS和MAXTRANS

堆组织表

6.3 索引组织表

数据在IOT中根据主键存储和排序。IOT特别适用于IR(信息检索)、空间和OLAP应用程序。

IOT名义上是表,但它们的段实际上是索引段。要显示空间使用等就要先把IOT表的名字转换成潜在的索引名。默认值是SYS_IOT_TOP_<object_id>,object_id是为表分配的内部对象ID。推荐在建表时指定索引名。

主要应用

对只包含主键列的表:使用堆组织表将有100%多的额外开销;

1. 构建自己的索引结构:例如自己实现一个提供大小写不敏感查询的类似函数索引

CREATE

TABLE emp AS SELECT * FORM scott.emp;

CREATE

TABLE upper_name

(x$ename,x$rid,

PRIMARY

KEY(x$ename,x$rid)

)

ORGANIZATION INDEX

AS

SELECT UPPER(ename),ROWID FROM

emp;

CREATE

OR REPLACE TRIGGER upper_ename

AFTER

INSERT OR UPDATE OR DELETE ON emp

FOR EACH

ROW

BEGIN

IF (UPDATING AND

(:OLD.ename||'x'<>:NEW.ename||'x'))

THEN

DELETE FROM

upper_name

WHERE

x$ename=UPPER(:OLD.ename)

AND

x$rid=:OLD.rowid;

INSERT INTO upper_ename(x$ename,x$rid)

VALUES (UPPER(:NEW.ename),:NEW.rowid);

ELSIF

(INSERTING)

THEN

INSERT INTO upper_ename(x$ename,x$rid)

VALUES (UPPER(:NEW.ename),:NEW.rowid);

ELSIF

(DELETING)

THEN

DELETE FROM

upper_name

WHERE

x$ename=UPPER(:OLD.ename)

AND

x$rid=:OLD.rowid;

END IF;

END;

2. 需要加强数据的共同定位或希望数据按特定的顺序物理存储时

对应Sybase和SQL Server用户,这种情况会采用聚簇索引,而这可能达到110%的额外开销,而IOT没有。经常用BETWEEN对主键或者唯一键进行查询,则会降低I/O数量。

主要选项

NOCOMPRESS/COMPRESS N

压缩N列,即对其中前N列相同的值进行压缩。从而能够允许更多数据进入Buffer Cache,代价是略多的CPU能量。

OVERFLOW

PCTTHRESHOLD N/INCLUDING column_name

索引段的存储要密集于普通数据段(每块的行数要多),一般PCTUSED是没有意义的。而OVERFLOW子句允许设置另一个段以允许IOT中的行数据太大时溢出的这个段中。它再次引入PCTUSED,这样PCTUSED和PCTFREE对OVERFLOW段有对于堆组织表中相同的含义。而使用方法是如下中的一种:

PCTTHRESHOLD——当行中数据超出此百分比,该行尾部的列溢出到溢出块;

INCLUDING——指定列之前的列均存入索引块,之后的列存入溢出块。

二次索引

只要主键是IOT,可以在索引中拥有索引。但不像其他一般索引,它不包含真正rowid(物理地址),而是基于主键IOT的逻辑rowid,作用稍小。对于IOT的二次索引访问实际有两个扫描执行(一般表只需一个扫描索引结构),一个在二次结构中,一个在IOT本身中。

6.4 索引聚簇表

Oracle中聚簇是存储一组表的方法,而不是如同SQL

Server、Sybase中那样(那是Oracle中的IOT)。概念上是通过聚簇码列将几张表“预连接”,尽可能将聚簇码列相同的几张表的行放入同一个块中。

CREATE CLUSTER

emp_dept_cluster

(deptno

NUMBER(2))

SIZE 1024;

CREATE INDEX

emp_dept_cluster_idx

ON CLUSTER

emp_dept_cluster;

CREATE TABLE dept

(deptno NUMBER(2) PRIMARY

KEY,

dname

VARCHAR2(14),

loc

VARCHAR2(3)

)

CLUSTER

emp_dept_cluster(deptno);

CREATE TABLE emp

(empno NUMBER PRIMARY

KEY,

ename

VARCHAR2(10),

...

deptno

NUMBER(2) REFERENCES dept(deptno)

)

CLUSTER

emp_dept_cluster(deptno);

BEGIN

FOR x

IN(SELECT * FROM scott.dept)

LOOP

INSERT

INTO dept VALUES(x.deptno,x.dname,x.loc);

INSERT

INTO emp

SELECT *

FROM scott.emp

WHERE

deptno=x.deptno;

END

LOOP;

END;

注意这里的插入方法,这将尽可能保证每个块中放置尽可能多的聚簇码值,并让可以“预连接”的两个表中的值尽可能在同一个块中。

DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)可用于检查rowid所属块。

很容易发现dept和emp有重复的rowid,表和rowid可以唯一确定行,rowid伪列只有在一张表中才是唯一的!

不使用聚簇的情况:

1.聚簇可能消极影响DML性能;

2.全扫描表的性能会受到影响——不仅仅扫描一个表,而是对多个表全扫描;

3.聚簇中的表不能TRUNCATE。

6.5 散列聚簇表

概念类似索引聚簇表,但用散列函数代替了聚簇码索引。Oracle采用行的码值,使用内部函数或者自定义的函数进行散列运算,从而指定数据的存放位置。这样没有在表中增加传统的索引,因此不能Range

Scan散列聚簇中的表,而只能全表扫描(除非单独建立索引)。

CREATE CLUSTER

hash_cluster

(hash_key NUMBER)

HASHKEYS 1000

SIZE 8192;

索引聚簇需要空间时是动态分配,而散列聚簇表在创建时确定了散列码数(HASHKEY)。Oracle采用第一个不小于HASHKEY的质数作为散列码数,将散列码数*SIZE就得到分配的空间(字节),可容纳HASHKEYS/TRUNC(BLOCKSIZE/SIZE)字节的数据。

性能上,散列聚簇表消耗较少I/O,较多CPU,所需执行时间较少,大体取决于CPU时间(当然可能要等待I/O,取决于配置)。

下列情况下使用散列聚簇表较为合适:

1. 在一定程度上精确知道整个过程中表中记录行数或者合理的上限,以确定散列码数;

2. 不大量执行DML,尤其是插入。更新不会产生显著的额外开销,除非更新HASHKEY,这样会导致行迁移;

3. 总是通过HASHKEY值访问数据。

6.6 嵌套表

两种使用嵌套表的方法:

1. PL/SQL代码中作为扩展PL/SQL语言;

2. 作为物理存储机制,以持久地存储集合。

嵌套表语法

创建嵌套表类型:

CREATE TABLE dept

(deptno

NUMBER(2) PRIMARY KEY,

dname

VARCHAR2(14),

loc VARCHAR2(13)

);

CREATE TABLE emp

(empno

NUMBER(4) PRIMARY KEY,

ename

VARCHAR2(10),

job

VARCHAR2(9),

mgr NUMBER(4) REFERENCES

emp,

hiredate DATE,

sal NUMBER(7,

2),

comm NUMBER(7,

2),

deptno NUMBER(2) REFERENCES

dept

);

INSERT INTO dept SELECT * FROM

scott.dept;

INSERT INTO emp SELECT * FROM

scott.emp;

CREATE OR REPLACE TYPE

emp_type

AS OBJECT

(empno

NUMBER(4),

ename

VARCHAR2(10),

job

VARCHAR2(9),

mgr

NUMBER(4),

hiredate DATE,

sal NUMBER(7,

2),

comm NUMBER(7,

2)

);

CREATE OR REPLACE TYPE

emp_tab_type

AS TABLE OF

emp_type;

使用嵌套表:

CREATE TABLE

dept_and_emp

(deptno

NUMBER(2) PRIMARY KEY,

dname

VARCHAR2(14),

loc

VARCHAR2(13),

emps

emp_tab_type

)

NESTED TABLE emps STORE AS

emps_nt;

可以在嵌套表上增加约束:

ALTER TABLE emps_nt ADD CONSTRAINT emps_empno_unique

UNIQUE(empno) ;

嵌套表不支持参照完整性约束,不能参考任何其他表甚至自己:

ALTER TABLE emps_nt ADD CONSTRAINT

mgr_fk

FOREIGN KEY(mgr) REFERENCES

emps_nt(empno);

会产生错误ORA-30730。

INSERT INTO

dept_and_emp

SELECT dept.*,

CAST(

MULTISET( SELECT empno, ename, job, mgr, hiredate, sal,

comm

FROM

emp

WHERE emp.deptno

= dept.deptno ) AS emp_tab_type )

FROM

dept;

MULTISET用来告诉Oracle子查询返回不止一行,CAST用来告诉Oracle将返回设置为一个集合类型。

查询时,嵌套表中的数据将在同一列中:

SELECT deptno, dname, loc, d.emps AS

employees

FROM dept_and_emp

d

WHERE deptno =

10;

Oracle同样提供方法去掉集合的嵌套,像关系型表一样处理(能够将EMPS列当作一个表,并自然连接且不需要连接条件):

SELECT d.deptno, d.dname,

emp.*

FROM dept_and_emp D, TABLE(d.emps)

emp;

按照“每行实际是一张表”的思想来更新:

UPDATE

TABLE(

SELECT emps

FROM

dept_and_emp

WHERE

deptno = 10

)

SET comm = 100;

但如果返回SELECT emps

FROM dept_and_emp WHERE deptno = 10少于一行,更新将失败(普通情况下更新0行是许可的),并返回ORA-22908错误——如同更新语句没有写表名一样;如果返回多于一行,更新也会失败,返回ORA-01427错误。这说明Oracle在使用了嵌套表后认为每一行指向另一个表,而不是如同关系型模型那样认为是另一个行集。

插入与删除的语法:

INSERT INTO TABLE

(SELECT emps FROM dept_and_emps WHERE

deptno=10)

VALUES

(1234,'NewEmp','Clerk',7782,SYSDATE,1200,NULL);

DELETE FROM TABLE

(SELECT emps FROM dept_and_emps WHERE

deptno=20)

WHERE

ename='SCOTT';

一般而言,必须总是连接,而不能单独查询嵌套表(如EMPS)中的数据,但是如果确实需要,是可以的。提示NESTED_TABLE_GET_REFS被用于EXP和IMP处理嵌套表。

SELECT

/*+NESTED_TABLE_GET_REFS+*/

NESTED_TABLE_ID, SYS_NC_ROWINFO$

FROM

"TKYTE"."EMPS_NT";

而我们察看EMPS_NT的表结构是看不到NESTED_TABLE_ID,SYS_NC_ROWINFO$两列的。对父表DEPT_AND_EMP来说NESTED_TABLE_ID是一个外键。

使用这个提示就可以直接操作嵌套表了:

UPDATE

/*+NESTED_TABLE_GET_REFS+*/ emps_nt

SET

ename=INITCAP(ename);

嵌套表存储

上例中,现实产生了两张表:

DEPT_AND_EMP

deptno

NUMBER(2)

dname

VARCHAR2(14)

loc

VARCHAR2(13)

SYS_NC0000400005$

RAW(16)

EMPS_NT

SYS_NC_ROWINFO$

NESTED_TABLE_ID

RAW(16)

empno

NUMBER(4)

ename

VARCHAR2(10)

job

VARCHAR2(9)

mgr

NUMBER(4)

hiredate

DATE

sal

NUMBER(7,2)

comm

NUMBER(7,2)

默认情况下,每个嵌套表列都产生一个额外的RAW(16)隐藏列,并在其上创建了唯一约束,用以指向嵌套表。而嵌套表中有两个隐藏列:SYS_NC_ROWINFO$是作为一个对象返回所有标量元素的一个伪列;另一个NESTED_TABLE_ID的外键回指向父表。

可以看到真实代码:

CREATE TABLE

TKYTE.DEPT_AND_EMP

(DEPTNO

NUMBER(2,0),

DNAME

VARCHAR2(14),

LOC

VARCHAR2(13),

EMPS

EMP_TAB_TYPE)

PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255

LOGGING

STORAGE(INITIAL 131072 NEXT

131072

MINEXTENTS 1 MAXEXTENTS 4096

PCTINCREASE 0 FREELISTS 1 FREELIST GROUP

1

BUFFER_POOL DEFAULT)

TABLESPACE USER

NESTED TABLE EMPS

STORE AS EMPS_NT

RETURN BY VALUE;

RETURN BY

VALUE用来描述嵌套表如何返回到客户应用程序中。

NESTED_TABLE_ID列必须是索引的,那么较好的解决办法就是使用IOT存储嵌套表。

CREATE TABLE

TKYTE.DEPT_AND_EMP

(DEPTNO

NUMBER(2,0),

DNAME

VARCHAR2(14),

LOC

VARCHAR2(13),

EMPS

EMP_TAB_TYPE)

PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255

LOGGING

STORAGE(INITIAL 131072 NEXT

131072

MINEXTENTS 1 MAXEXTENTS 4096

PCTINCREASE 0 FREELISTS 1 FREELIST GROUP

1

BUFFER_POOL DEFAULT)

TABLESPACE USER

NESTED TABLE EMPS

STORE AS EMPS_NT

((empno NOT NULL,

UNIQUE(empno),

PRIMARY

KEY(nested_table_id,empno))

ORGANIZATION

INDEX COMPRESS 1)

RETURN BY VALUE;

这样与最初默认的嵌套表相比,使用了较少的存储空间并有最需要的索引。

不使用嵌套表作为永久存储机制的原因

1.增加了RAW(16)列的额外开销,父表和子表都将增加这个额外的列;

2.当通常已经有唯一约束时,父表上的唯一约束是额外开销;

3.没有使用不支持的结构(NESTED_TABLE_GET_REFS),嵌套表不容易使用。

一般推荐在编程结构和视图中使用嵌套表。如果要使用嵌套表作为存储机制,确保嵌套表是IOT,以避免NESTED_TABLE_ID和嵌套表本身中索引的额外开销。

6.7 临时表

Oracle的临时表与其他数据库中的不同,其定义是“静态”的。以事务(ON COMMIT

DELETE ROWS)或者会话(ON COMMIT

PRESERVE ROWS)为基础,只是说明数据的生命期,而在数据库中创建临时表一次,其结构总是有效的,被作为对象存在数据字典中了,这样也就允许对临时表建立视图、存储过程中用静态SQL引用临时表等等。

在实际开发中,考虑到DDL是消耗较大的操作,应该避免在运行时操作,而是将应用程序需要的临时表在程序安装时就创建,而只是在存储过程中简单的INSERT、SELECT。

临时表不支持的永久表的特性有:

1. 不能用参照完整性约束,也不能被参照完整性约束所引用;

2. 不能有VARRAY或者NESTED

TABLE类型的列;

3. 不能是IOT;

4. 不能是索引或者散列聚簇;

5. 不能分区;

6. 通过ANALYZE命令不能产生统计信息,也即是说优化器在临时表上没有真正的统计功能。

由于缺少统计功能,那么CBO(基于成本的优化器)的性能将受到极大的影响,因此应当尽可能使用INLINE

VIEW。

要让临时表拥有正确的统计信息,CBO产生正确的决策,可以先建立一张结构与临时表完全相同的普通表:

CREATE TABLE

temp_all_objects

AS

SELECT * FROM all_objects WHERE

1=0;

CREATE INDEX temp_all_objects_idx ON

temp_all_objects(object_id);

选择插入代表性数据后进行分析:

...

ANALYZE TABLE temp_all_objects COMPUTE STATISTICS FOR

ALL INDEX;

BEGIN

DBMS_STATS.CREATE_STAT_TABLE(ownname =>

USER,

stattab =>

'STATS');

DBMS_STATS.EXPORT_TABLE_STATS(ownname =>

USER,

tabname

=> 'TEMP_ALL_OBJECTS',

stattab

=> 'STATS');

DBMS_STATS.EXPORT_INDEX_STATS(ownname =>

USER,

tabname

=> 'TEMP_ALL_OBJECTS_IDX',

stattab

=> 'STATS');

END;

建立临时表:

DROP TABLE

temp_all_objects;

CREATE GLOBAL TEMPORARY TABLE

temp_all_objects

AS

SELECT * FROM all_objects WHERE

1=0;

导入正确的信息后CBO将使用这些信息决定执行模式:

CREATE INDEX temp_all_objects_idx ON

temp_all_objects(object_id);

BEGIN

DBMS_STATS.IMPORT_TABLE_STATS(ownname =>

USER,

tabname

=> 'TEMP_ALL_OBJECTS',

stattab

=> 'STATS');

DBMS_STATS.IMPORT_INDEX_STATS(ownname =>

USER,

tabname =>

'TEMP_ALL_OBJECTS_IDX',

stattab

=> 'STATS');

END;

6.8 对象表

基于类型(Type)创建的表,而不是作为列的集合。创建语法:

CREATE TABLE t OF

some_type;

对于下例:

CREATE OR REPLACE TYPE

address_type

AS OBJECT

(city

VARCHAR2(30),

street

VARCHAR2(30),

state

VARCHAR2(2),

zip

NUMBER

);

CREATE OR REPLACE TYPE

person_type

AS OBJECT

(name

VARCHAR2(30),

dob

DATE,

home_address

address_type,

work_address

address_type

);

CREATE TABLE people OF

person_type;

通过执行如下语句,可以看到数据库中实际存放的结构:

SELECT

name,segcollength

FROM SYS.COL$

WHERE obj#=(SELECT

object_id

FROM user_objects

WHERE

object_name='PEOPLE');

PEOPLE

SYS_NC_OID$

16

SYS_NC_ROWINFO$

1

NAME

30

DOB

7

HOME_ADDRESS

1

SYS_NC00006$

30

SYS_NC00007$

30

SYS_NC00008$

2

SYS_NC00009$

22

WORK_ADDRESS

1

SYS_NC00011$

30

SYS_NC00012$

30

SYS_NC00013$

2

SYS_NC00014$

22

SYS_NC_OID$是系统为表产生的Object

ID,RAW(16),其上有唯一性索引。它是一主键为基础,并不是系统产生的,是一个伪列,且没有在硬盘上真正消耗空间;

SYS_NC_ROWINFO$类似于嵌套表中,可作为单独一列返回整行;

NAME,

DOB是表中原有标量;

HOME_ADDRESS,

WORK_ADDRESS可作为单个对象,返回所代表的列的集合;

SYS_NCnnnnn$是内嵌对象类型的标量实现。

第 7

章 索引

7.1 索引类别

B*树索引——传统索引,从码转向行

索引组织表

B*树聚簇索引——从聚簇码转向包含与行相关的聚簇码的块

反向码索引——更均匀的分配索引条目

降序索引——允许数据在索引中降序排列

位图索引

基于函数的索引

应用程序域索引

interMedia文本索引

7.2 B*树索引

索引中的叶结点实际上是双向链表,这样不必经过上级结点可以直接Range

Scan。在B*树中实际不会出现不唯一的索引,对不唯一索引只要加上ROWID就唯一了。对于排序,不唯一索引先根据索引值排序,然后根据ROWID排序;唯一索引根据索引值排序。

B*树一般2-3层,且自动平衡。

反向码索引

实际就是将索引值的内部表示(高低位)反转,这样相邻的索引值之间距离变远,便于并发。缺点是不能支持所有正常索引的功能,例如无法支持WHERE

x>5这样的谓词。

降序索引

使用环境

1. 处理表中很多行,但索引就能替代表;

如对一张已经建立了索引的表COUNT(*)

2. 访问表中极少的行,一般2-3%(如果表中有多列或较宽的列,则此百分比可升至20-25%)。

否则效率不及全表扫描。原因在于由索引访问块,则访问顺序几乎随机,每个块可能要访问多次,则不及全表的块一次性扫描效率高。但这同样需要考虑表中特定的数据,若数据在表中基本按主键顺序排列,则使用索引又会效率很高——每个块不会或很少访问多次。

视图USER_INDEXES中CLUSTERING_FACTOR列说明了数据存放的随机程度:

若CLUSTERING_FACTOR接近块的数量,则表较易排序,单个叶块上的索引条目趋向于指向同一个块上的列;

若CLUSTERING_FACTOR接近行数,则表是随机排序的。

7.3 位图索引

在7.3版本中加入,而8i标准版不支持。为数据仓库等特定查询环境设计,不应用在OLTP系统或许多并行会话经常更新数据的系统。使用的另一个基本原则是基数(字段不同的取值)较低。总体上适合集中读取的环境,而极不适合集中写入的环境。原因在于任何需要更新同一个位图索引条目的修改都将锁定整个位图,严重抑制了并发性。通常建立位图索引的时间短过B*树索引。

7.4 基于函数的索引

在8.1.5版加入,8i标准版不支持。

实现前提

1. 在自己的模式中的表上创建基于函数的索引,必须具有系统特权QUERY

REWRITE;对其他用户,必须具有系统特权GLOBAL

QUERY REWRITE;

2. 使用CBO;

3. 必须设置如下会话或系统变量:

QUERY_REWRITE_ENABALED=TRUE

QUERY_REWRITE_INTEGRITY=TRUSTED

这些参数可以通过ALTER

SESSION或者ALTER

SYSTEM来修改,或者直接修改init.ora。其中QUERY_REWRITE_INTEGRITY=TRUSTED说明系统可以信任函数,不会产生二义性结果;

4. 使用SUBSTR来限定从用户定义的函数中返回的VARCHAR2或RAW类型的值。

注意

索引项的大小应在数据块的1/3以内,对于普通8K而言就是3218字节(否则会报ORA-01450错误代码)。因此,对于返回VARCHAR2或RAW类型值的函数应用SUBSTR来限制。为了掩藏其复杂性并提高灵活性(允许以后更改SUBSTR的大小),我们可以使用视图来掩盖(即将相应字段更换为SUBSTR后的值),系统同样会识别出基于函数的索引。

对于8.1.7之前的系统要注意,使用to_date作为建立索引的函数时会报ORA-01743错误代码,解决方法是自己实现一个to_date的外壳。

对于用户自定义的函数建立索引后,不能Direct

Path导入,而对系统提供的函数不受影响。

鉴于每次插入或更新,对应函数都执行一次,其修改的效率降低了很多,但带来很多查询的效率提高。

7.5 应用程序域索引

又称为“可扩展的索引”,允许创建自己的索引结构,如同系统提供的一样工作。

7.6 常见问题解答

索引能否在视图中使用

系统是用视图的定义来访问数据,较好的索引基表,就能够提高视图效率。

索引和NULL

除了B*树索引聚簇的特殊情况,B*树索引不存储NULL的条目,而位图索引和聚簇索引存储所有NULL条目。

利用这一特性,若表中某列大部分取值一致,则可将其修改为NULL,将极大的缩小索引占用空间。

外键上的索引

非索引的外键是导致死锁的主要原因。父表修改时将全表锁定子表,若关联着的子表外键无索引,则每次删除父表中的一行就会对子表全表扫描一次。

不需要外键索引的情况:

不从父表中删除;

不更新父表主键或唯一键的值;

不连接父表和子表。

未用到索引的原因

1. 一张T(x,y)上有索引的表T,查询SELECT *

FROM T WHERE y=5,由于谓词未包含X,则必须全扫描索引条目,则优化器通常选择对T全表扫描;查询SELECT x,y

FROM T WHERE y=5,则优化器会注意到为得到x和y,不必进入表,且一般索引小于表,则CBO会选择快速全扫描索引。

2. 查询SELECT

COUNT(*) FROM T,表上有一个B*树索引,则考虑到索引可能在一系列包含空值的列上,优化器选择全扫描表。

3. 对列使用了函数,而索引只是基于列的。

4. 一个字符列上有索引,但谓词是indexed_column=5,这里系统隐含使用了to_number函数,同3,不会使用索引。

5. 使用索引实际会降低速度。

6. 很长时间没有分析表了,表的增长较快,这样CBO会作出错误的判断。

索引中空间重用

只要出现的行可重用,索引块上的空间就能重用;

当一个索引块为空时将加入FREELIST,从而可以重用,但和堆组织表不同,即便只有一个索引,也会占据一个块。

第 8

章 导入和导出

8.1 IMP/EXP的工作原理

大量导出

EXP和一般文件一样,在支持搜索的设备(即文件系统?)上能产生的文件大小是有限制的,它使用一般OS文件的API,在32位系统中限制的文件大小为2GB。已知以下4种解决方法。

1. 使用FILESIZE参数

该参数在8i中引入。设置后将限制每个导出的DMP文件的大小,问题在于必须大致估计文件个数(即总导出量),并提供FILE参数列表,否则将产生交互式会话,请求提供文件名,而对于定时无人值守的操作,长时间无响应会产生错误。另一方面,将多个DMP文件导入时可以一次性提供多个文件名,即便实际文件不存在,只会提示警告而不会出错。

2. 导出较小的数据文件

比如按方案导出等

3. 导出到OS管道

此方法目前仅应用于UNIX。

#!/bin/csh -f

# Set this to the userid you want to perform the

export as I always use OPS$ (os

# authenticated) accounts for all jobs that will be

run in the background. In that

# way a password never appears in a script file or in

the ps output.

setenv UID /

# This is the name of the export file. SPLIT will use this to

name the pieces of

# the compressed DMP

file.

setenv FN

exp.`date +%j_%Y`.dmp

# This is the name of the named pipe we will

use.

setenv PIPE

/tmp/exp_tmp_ora8i.dmp

# Here I limit the size of the compressed files to

500 MB each. Anything less

# than 2 GB would be

fine.

setenv MAXSIZE 500m

# This is what we are going to export. By default I

am doing a full database

# export.

setenv EXPORT_WHAT "full=y

COMPRESS=n"

# This is where the export will go

to.

cd

/nfs/atc-netapp1/expbkup_ora8i

# Clear out the last

export.

rm expbkup.log export.test exp.*.dmp* $PIPE

# Create the named

pipe.

mknod $PIPE p

# Write the datetime to the log

file.

date >

expbkup.log

# Start a gzip process in the background. Gzip will

read the pipe and put the

# compressed data out to split. Split will then create 500 MB files out of

the

# input data adding .aa, .ab, .ac, .ad, ... file

extensions to the template name

# found in $FN.

( gzip < $PIPE ) | split -b $MAXSIZE - $FN.

&

# Now, start up export. The Gzip above is waiting for

export to start filling the

# pipe up.

exp userid=$UID buffer=20000000 file=$PIPE

$EXPORT_WHAT >>& expbkup.log

date >>

expbkup.log

# Now the export is done, this is how to IMP. We need

to sort the filenames and

# then simply cat their contents into gunzip. We

write that into the pipe. IMP

# will then read that pipe and write what it would do

to stderr. The >>& in

the

# csh redirects both stdout and stderr for

us.

date >

export.test

cat `echo $FN.* | sort` | gunzip > $PIPE

&

imp userid=$UID file=$PIPE show=y full=y

>>& export.test

date >>

export.test

# Clean up the pipe, we don't need it

anymore.

rm -f $PIPE

4. 导出到一个不支持搜索的设备

仅用于UNIX。指定设备名,可以直接将数据导出到磁带设备中。

数据子集

即设置QUERY参数。但条件中往往含有各个OS上的保留字符,那么用par(参数)文件的形式更通用一点。如:

Windows下:

C:\exp>exp userid=… tables=t query=”””where

object_id<5000”””

UNIX下:

$exp userid=… tables=t query=\ ”where

object_id\<5000\”

使用参数文件:

exp.par: query=”where object_id<5000”

exp userid=… tables=t

parfile=exp.par

数据传输

即直接将一个数据库上的数据文件附加到另一个数据库中。

规则:

1. 源数据库与目标数据库必须运行在相同的硬件平台上;

2. 源数据库与目标数据库必须使用相同的字符集;

3. 源数据库一定不能有与目标表空间同名的表空间;

4. 源数据库与目标数据库的块大小一样;

5. 被传输的表空间必须是完备的,如其含有索引等但不包含对应的表;

6. 源数据库在导出元数据和复制数据文件过程中必须将导出的表空间设为只读模式;

7. SYS拥有的对象无法传输;

8. 不能传输的对象有:快照/物化视图、基于函数的索引、区域索引、领域引用(Scoped

Refs)和多个接收者的AQ。

检测表空间是否完备:

exec sys.dbms_tts.transport_set_check( 'tb1', TRUE

);

select * from

sys.transport_set_violations;

exec sys.dbms_tts.transport_set_check( 'tb2', TRUE

);

select * from

sys.transport_set_violations;

exec sys.dbms_tts.transport_set_check( 'tb1, tb2',

TRUE );

select * from

sys.transport_set_violations;

无返回则说明该(套)表空间完备。

开始传输:

alter tablespace tts_ex1 read

only;

alter tablespace tts_ex2 read

only;

host exp userid="""sys/change_on_install as sysdba"""

transport_tablespace=y

tablespaces=(tts_ex1,tts_ex2)

host XCOPY c:\oracle\oradata\tkyte816\tts_ex?.dbf

c:\temp

alter tablespace tts_ex1 read

write;

alter tablespace tts_ex2 read

write;

imp file=expdat.dmp userid="""sys/change_on_install

as sysdba""" transport_tablespace=y

"datafiles=(c:\temp\tts_ex1.dbf,c:\temp\tts_ex2.dbf)"

alter tablespace tts_ex1 read

write;

第一頁    上一頁    第1頁/共3頁    下一頁    最後頁
第01頁 第02頁 第03頁 
 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有