約束、檢視、序列、偽列和索引
前言
約束條件用於保證資料的完整性。主要有主鍵約束(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
[email protected] 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