约束、视图、序列、伪列和索引
前言
约束条件用于保证数据的完整性。主要有主键约束(primary key)/非空约束(not null)、唯一约束(unique) 检查约束(check)和外键约束(foreign key).
正文
约束
主键约束(primary key)
主键约束包括了非空和唯一
create table 表名(字段名 字段类型(长度) 约束条件);
1.创建自己定义名称约束
create table 表名(字段名 字段类型(长度),constraint 约束名 约束类型(字段名));
注:能够通过user_constraints数据字典来查询约束。
非空约束(not null)
检查约束(check)
create table t_test(id number(10);sex char(2); constraint test_sex check (sex in('男'。‘女’)));--能够通过在字段后面加 default 值。来设置默认值;在使用默认值时使用defaultkeyword。
注:元组上的约束的定义
元组级别的限制能够设置不同属性之间取值的相互约束条件
check(ssex='女' or sname NOT like 'MS.%');--当学生性别为男时。其名字不能以MS.开头。
外键约束(foreign key 字段名 references 表名(字段名)).
外键字段能够为空,或者引用自依赖的父项。
设置级联
1.赋予空值
foreign key(外键字段) references 表名(字段) on delete set null;
2.级联删除
foreign key(外键字段) references 表名(字段) on delete cascade;
联合主键
constraint pk_t_emp primary key (字段1,字段2);
DDL操作约束
alter table 表名 drop contraints 约束名称。
alter table 表名 add contraints 约束名称 约束类型(字段);
alter table 表名 modify (字段 字段类型 要加入的约束);
视图
1.create or replace view 视图名 as select * from emp;
2.视图是一种虚拟的表,具有和物理表同样的功能,能够对视图进行增、改和查询。
视图一般是一个表或多个表的行或列的子集。
3.对视图的改动不影响基本表。
4.视图使我们获得数据更easy。
注:
复杂视图的定义是。视图中的数据不能直接通过表获得,必须通过计算来获得;复杂视图的查询字段必须取别名。
序列
序列是数据库中特有的一组能够实现自己主动增长的数字。
create sequence 序列名 increment by 每次增长的步长 start with 起始值。
1.select 序列名.nextval from dual.--获取序列的下一个值;获取序列的当前值採用currval属性。
伪列
oracle特有的默认提供给每个表的。以便实现某些功能。
rownum
表示每条记录的序号(查到结果集后才分配的序号),经常常使用于分页。
rowid
表示每条记录的唯一标识(一组32为的字符串),可用来获取记录的物理地址
样例1:删除表中的同样记录
方法一:
delete from t_table t1 where t1.rowid!=(select max(rowid) from t_table t2 where t1.id=t2.id and t.name=t2.name);;--当中 t1.id=t2.id and t.name=t2.name是定义同样记录的条件
方法二:
delete from t_table where roeid not in(select max(rowid) from t_table group by 字段一,字段二);
样例1:删除表中不反复的记录
delete from t_table t1 where t1.rowid=(select max(rowid) from t_table t2 where t1.id=t2.id and t.name=t2.name) and t1.rowid=(select min(rowid) from t_table t2 where t1.id=t2.id and t.name=t2.name) ;
应用于分页
1.三目运算来计算总页数 totalpage=sum/pagesize+sum%pagesize==0?0:1;//计算总页数,sum为总记录数
2.第page页的记录的起始位置和结束位置分别为:
pagesize*(page-1)+1。起始位置
pagesize*page;j、结束位置
注:
1.能够使用差集(minus)在数据库查询中实现分页,但效率低'
2.经常使用子查询将rownum作为还有一结果集的字段来实现分页。
select ee.* from(select e.* , rownum rr from (select * from emp where sal is not null order by sal ) e )ee where ee.rr berween &start and &end。
3.rownum的分页地java代码演示样例
package com.zhongxin.backstage.biz.impl; import java.util.List; import com.zhongxin.backstage.bean.CardPage; import com.zhongxin.backstage.bean.PlatePage; import com.zhongxin.backstage.biz.CardContextBiz; import com.zhongxin.backstage.dao.CardContextDao; import com.zhongxin.backstage.dao.PlateContextDao; import com.zhongxin.exception.DAOException; import com.zhongxin.entity.MainCard; import com.zhongxin.entity.Plate; import com.zhongxin.factory.Factory; import com.zhongxin.util.DeleteSpaceUtil; public class CardContextBizImpl implements CardContextBiz { private int pageSize=10; private CardContextDao dao=(CardContextDao) Factory.getImpl("CardContextDaoImpl");//定义dao层 public CardPage searchAllCard(int pageNum) throws DAOException { // 获取全部的帖子 //计算分页的页面总数 CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard "; int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 List list=dao.searchCardByPage(start,end); cardPage.setCard(list); return cardPage; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public CardContextDao getDao() { return dao; } public void setDao(CardContextDao dao) { this.dao = dao; } public CardPage searchCardById(int pageNum,long id) throws DAOException { //依据id获取主贴信息 //计算分页的页面总数 CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where cardId="+id; int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 List list=dao.searchCardByPage(start,end,id); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardBySendPeople(int pageNum, String name) throws DAOException { //依据发帖人获取主贴细信息 //计算分页的页面总数 CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where name='"+name+"'"; int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 List list=dao.getCardByPageAndPeopleName(start,end,name); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardByTime(int pageNum, String time) throws DAOException { // 依据时间获取主贴 //计算分页的页面总数 if(time.contains(".")){ time=time.substring(0,time.lastIndexOf("."));//去掉时间的秒的小数点 } CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where time=to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')"; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where time=to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')"+") t) t1" + " where t1.r between "+start+" and "+end; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } //SQL> select * from emp where hiredate between (to_date('1981-2-20','yyyy-mm-dd')) and (to_date('1981-2-23','yyyy-mm-dd')); public CardPage searchAllCardByTimeInnerOneDay(int pageNum, String time) throws DAOException { //依据某个时间点的一天内查询的主贴 //计算分页的页面总数 if(time.contains(".")){ time=time.substring(0,time.lastIndexOf("."));//去掉时间的秒的小数点 } CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where time between to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')"+"and to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')+1"; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?
0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where time between to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')"+"and to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')+1"+") t) t1" + " where t1.r between "+start+" and "+end; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardByOrderTime(int pageNum, String time) throws DAOException { // 依据查询某个时间点至今的有主贴,并按时间排序 //计算分页的页面总数 if(time.contains(".")){ time=time.substring(0,time.lastIndexOf("."));//去掉时间的秒的小数点 } CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where time between to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')"+"and sysdate"; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where time between to_date('"+time+"','yyyy-mm-dd hh24:mi:ss')"+"and sysdate"+") t) t1" + " where t1.r between "+start+" and "+end+" order by time "; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardBySubject(int pageNum, String subject) throws DAOException { //依据主题获取主贴信息 CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where subject='"+subject+"'"; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where subject='"+subject+"') t) t1" + " where t1.r between "+start+" and "+end+" order by subject "; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardByLikeSubject(int pageNum, String subject) throws DAOException { //依据帖子的主题查询主贴支持模糊查询 subject=DeleteSpaceUtil.deleteSpace(subject);//除掉模糊查询的keyword的中间空白 CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where subject like '%"+subject+"%'"; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where subject like '%"+subject+"%') t) t1" + " where t1.r between "+start+" and "+end+" order by time "; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardByNum(int pageNum, int num) throws DAOException { //依据回帖数查询主贴 CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where replyNum="+num; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where replyNum="+num+") t) t1" + " where t1.r between "+start+" and "+end+" order by replyNum "; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardByGreateNum(int pageNum, int num) throws DAOException { // if(num<0){ num=0; } CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where replyNum>="+num; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where replyNum>="+num+") t) t1" + " where t1.r between "+start+" and "+end+" order by replyNum "; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } public CardPage searchAllCardByPerfectCard(int pageNum, String perfectCard) throws DAOException { // 查看精品帖 //进行页面显示的内容与数据库的表示转化 int num=0; if("yes".equals(perfectCard)){ String sql="select count(*) from tb_mainCard where perfectCard!="+num; System.out.println(sql); CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where perfectCard!="+num+") t) t1" + " where t1.r between "+start+" and "+end+""; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; }else{ String sql="select count(*) from tb_mainCard where perfectCard="+num; CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where perfectCard="+num+") t) t1" + " where t1.r between "+start+" and "+end+""; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } } public CardPage searchAllCardByPlateName(int pageNum, String plateName) throws DAOException { //依据板块获取主贴 CardPage cardPage=(CardPage) Factory.getImpl("CardPage"); String sql="select count(*) from tb_mainCard where plateName='"+plateName+"'"; //System.out.println(sql); int totalCount=dao.getTotalCount(sql); int totalPage=(totalCount/this.getPageSize())+(totalCount%this.getPageSize()==0?0:1); //处理请求页面大于总页面的情况 if(pageNum>totalPage){ pageNum=totalPage; } if(pageNum<=0){ pageNum=1; } cardPage.setTotalPage(totalPage); cardPage.setCurrPage(pageNum); if(totalCount==0){ return cardPage; } //使用基于查询的分页 int start=(pageNum-1)*this.getPageSize()+1; int end=pageNum*this.getPageSize(); //调用dao层的方法获取显示数据 String sql2="select * from (select rownum r,t.* from ("+"select * from tb_mainCard where plateName='"+plateName+"') t) t1" + " where t1.r between "+start+" and "+end+" order by replyNum "; List list=dao.getCard(sql2); cardPage.setCard(list); return cardPage; } public boolean deleteCardById(long id) throws DAOException { //删除主贴 int num =dao.deleteCardById(id); //System.out.println(num); if(num==1){ return true; }else{ return false; } } public boolean deleteCardById(String[] arrId) throws DAOException { //删除选中的主贴 return dao.deleteCardByArrId(arrId); } }
索引
高速的查找定位到某条记录(底层採用rowid来实现);没有索引查找时,将採用全表扫描(full table scan)
注:
1.查找索引能够使用user_indexes数据字典。
2数据库.默觉得表中的主键和唯一键建立索引。
自己定义索引
create index 索引名 on 表名(字段名)。
不应该应用索引的情况
1.经常进行更新操作的字段
2.表小,查询结果集大
3.不经常使用的字段
应用索引的情况
1.经经常使用来查询的字段
2.当表的数据量非常大且查询的结果集较小
3.当前字段值非常多为空的字段
4.经经常使用来作为联合查询的字段
5.外键字段
注:说说你对索引的认识(索引的结构、对dml的影响、对查询的影响和为什么提高查询性能)?
1。
索引有b-tree和cluster等类型。oracle使用了一个复杂的自平衡b-tree结构。
2.通常来说在表上建立适当的索引,在查询时会改进查询性能。
3.但在进行插入、改动和删除是。同一时候会进行索引的改动,在性能上有一定的影响。索引通常能够提高select、update和delete的性能。但会降低insert的速度。
4,。有索引且在查询条件使用索引时,数据库会先读取索引,再依据索引内容和查询条件来查询出rowid,最后依据rowid取出须要的数据。
因为索引内容通常比全表内容要少非常多,因此通过先读索引能够降低I/O,提高查询性能。
对索引操作的法则
1.避免对索引字段进行计算操作
2.避免在索引字段上使用not、<、>、和!=
3.避免在索引列上使用is null 和 is not null。
4.避免在索引列上出现数据类型转换
5.避免在索引字段上使用函数
6.避免在建立索引的列中使用空值.
数据字典
存储描写叙述对象(表。序列、视图、触发器、过程、函数等)信息的表或视图称为数据字典。
user_XXX 表示当前用户的相关信息的数据字典
user_tables/user_constraints/user_indexes/user_sequences/user_views/user_objects
比如:select distinct object——type from user_objects;--查看全部的对象
user_all_XXX 当前用户所能訪问的对象的数据字典
dba_xxx 当前数据库下得全部对象的数据字典
总结
table space
一个数据库划分为一个或多个逻辑单元,该逻辑单元称为表空间。block(块)组成extent(长度),extent组成segment(段)。segment组成tablespace。
block
1.block是Oracle中存储数据块的最小单位,所以数据终于都是存储在block中。它也被称为逻辑blocks或是页(pages)。
2.每个操作系统都有自己的block size。
而这里的block是Oracle自己的,不同于OS的blocks。能够通过设置DB_BLOCK_SIZE设置Oracle的block为OS的block的几倍。从而降低不必要的I/O。无论block中存放的数据是表、索引还是cluster data,block的结构都是一致:
3. @ block header: 这里主要存储一些数据块的基本信息,如数据块地址,块类型(table data, index等),以及一些事务信息。
为了加强理解,我们dump一下block看看:
SQL> select dbms_rowid.rowid_relative_fno(rowid) as fno, dbms_rowid.rowid_block_number(rowid) from t1 where b=1;
FNO DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
———- ————————————
4 388
SQL> alter system dump datafile 4 block 388;
在dump file中,我们看到
Block header dump: 0×01000184
Object id on Block? Y
seg/obj: 0xcd17 csc: 0×00.8d80b itc: 2 flg: E typ: 1 – DATA
brn: 0 bdba: 0×1000181 ver: 0×01 opc: 0
inc: 0 exflg: 0
# 下面是一些比較重要的事务信息。每当一个事务開始时,都要获得一个ITL entry, 否则将会出现ITL 等待。
Itl Xid Uba Flag Lck Scn/Fsc
0×01 0×0002.005.0000010b 0×00800024.0128.32 –U- 66 fsc 0×0000.0008d8f3
0×02 0×0000.000.00000000 0×00000000.0000.00 —- 0 fsc 0×0000.00000000
data_block_dump,data header at 0xceb6864
4. @ table directory 记录该块中 table rows 的信息,例如以下所看到的:
===============
tsiz: 0×1f98
hsiz: 0×96
pbl: 0×0ceb6864
bdba: 0×01000184
76543210
flag=——–
ntab=1 // no. of tables, 除了cluster 以外。普通情况都为一
nrow=66 // 该block 上 rows 的数目
frre=-1
fsbo=0×96
fseo=0×402
avsp=0×36c
tosp=0×36c
5.@ row directroy 记录该块中记录的每一条记录的地址信息。例如以下所看到的:
0×12:pri[0] offs=0×402
0×14:pri[1] offs=0×46d
0×16:pri[2] offs=0×4d8
…
…
0×92:pri[64] offs=0×1ec2
0×94:pri[65] offs=0×1f2d
终于的记录条数应该和table directory 中的nrows相等。
这部分空间一旦被分配,将不可能收回,仅仅能在有新行insert时被重用。
** overhead:在block中,上述的header、table directory和row directory被合称为overhead。
6. @ row data 记录表中的实际数据。
7. @ free space 该部分主要用于update,insert等操作。 同一时候ITL entry 也能够在该部分获得。
附注: 在data block中的free space的使用与优化
1.当数据被delete或update时,可能引起block产生free space对此:
①假设有insert语句与对应释放block space的语句在同一个transaction中,则insert能够使用刚刚释放的block space。
②假设insert语句与对应的释放block space的语句不在同一个transaction中。则释放的block space仅仅有在事务被commit之后才干被使用。
Oracle当发生下面两种情况会进行free space的合并:insert或update操作视图使用一个有足够free space的block;free space存在大量碎片,无法进行数据的insert等。
2. row的链接与迁移:
当一条记录row的数据太大时。可能无法放在一个block中,这样的情况下Oracle往往会使用chain(链接)的方法;此外。当one row被update后,数据量增大。当前的block已经不能全然容纳时,Oracle会把该row数据整个迁移(migrates)到其它的数据块中。但在原来row的位置上保存一个指针。链接到新的地址上,大量的迁移、链接将会降低DB的I/O性能。
extent
extent 是每次分配给一个对象的逻辑最小单位,是由一定数量连续的block组成。一个或多个extent又组成了一个segment。
1. @ Extent的分配:
对于本地管理表空间。DB会先确定能够分配extent的候选datafile,随后查询该datafile的bitmap,确定是否有所需大小的连续空暇blocks。直到找到满足的datafile。假设使用dictionary managed tablespace,则是去查询数据字典。而不是datafile头部的bitmap信息。
另外,因为某些原因,假设想手工非配extent时。能够使用alter table table_name allocate extent。
2. @ Extent的收回:
1)当一个extent被分配给了某个object。除非这个obj被drop,否则extent将不会被其它obj所使用。除非 trauncate … drop storage.或者alter table … dealocate unused.(以上两种方法都不适用于index)。
另外。对于rollback segments。假设指定了optimal參数。oracle会自己dealocate一些extent。
2) 在dictionary managed tablespace中,假设所请求的ext 大于各个free extents 大小,这是oracle将聚合临近的extent。形成一个更大的extent。
在local managed tablespace中。则无此限制。 一旦extent 被分配和回收,对应的文件头bitmap或者数据字典都会被更新。
segment
它是extents的集合,它包括了在表空间中所包括的详细逻辑存储机构的全部extents。
比如一个未分区的table,index, cluster被成为一个段,一个被分区的index,table的一个partition 被成为一个段。对于temporary segment。主要用于排序等操作。仅仅有当DB的内存无法存放对应的排序操作并无法找到其它更好的解决的方法时。才会在暂时表空间中创建temporary segment。
1.下面语句都可能要创建temporary segment。
CREATE INDEX
SELECT ... ORDER BY
SELECT DISTINCT ...
SELECT ... GROUP BY
SELECT . . . UNION
SELECT ... INTERSECT
SELECT ... MINUS