Oracle的大表,小表與全表掃描


大小表區分按照數據量的大小區分;

通常對於小表,Oracle建議通過全表掃描進行數據訪問,對於大表則應該通過索引以加快數據查詢,當然如果查詢要求返回表中大部分或者全部數據,那么全表掃描可能仍然是最好的選擇。
從V$SYSSTAT視圖中,我們可以查詢得到關於全表掃描的系統統計信息: 

SQL> col name for a30 
SQL> select name,value from v$sysstat
2 where name in ('table scans (short tables)','table scans (long tables)');

NAME VALUE
------------------------------ ----------
table scans (short tables) 828
table scans (long tables) 101


其中table scans (short tables)指對於小表的全表掃描的此時;table scans (long tables)指對於大表的全表掃描的次數。
從Statspack的報告中,我們也可以找到這部分信息:

Instance Activity Stats for DB: CELLSTAR Instance: ora8i Snaps: 20 - 

Statistic Total per Second per Trans 
--------------------------------- ---------------- ------------ ------------ 
。。。。。。
table scan blocks gotten 38,228,349 37.0 26.9 
table scan rows gotten 546,452,583 528.9 383.8 
table scans (direct read) 5,784 0.0 0.0 
table scans (long tables) 5,990 0.0 0.0 
table scans (rowid ranges) 5,850 0.0 0.0 
table scans (short tables) 1,185,275 1.2 0.8 

通常,如果一個數據庫的table scans (long tables)過多,那么db file scattered read等待事件可能同樣非常顯著,和以上數據來自同一個report的Top5等待事件就是如此:

Top 5 Wait Events 
~~~~~~~~~~~~~~~~~ Wait % Total
Event Waits Time (cs) Wt Time
-------------------------------------------- ------------ ------------ -------
log file parallel write 1,436,993 1,102,188 10.80
log buffer space 16,698 873,203 8.56
log file sync 1,413,374 654,587 6.42
control file parallel write 329,777 510,078 5.00
db file scattered read 425,578 132,537 1.30 

數據庫內部,很多信息和現象都是緊密相關的,只要我們加深對於數據庫的了解,在優化和診斷數據庫問題時就能夠得心應手。

Oracle通過一個內部參數_small_table_threshold來定義大表和小表的界限。缺省的該參數等於2%的Buffer數量,如果表的大小小於該參數定義,Oracle認為該表為小表,否則Oracle認為該表為大表。
我們看一下Oracle9iR2中的情況:

SQL> @@GetParDescrb.sql
Enter value for par: small
old 6: AND x.ksppinm LIKE '%&par%'
new 6: AND x.ksppinm LIKE '%small%'

NAME VALUE DESCRIB
------------------------------ -------------------- ------------------------------------------------------------
_small_table_threshold 200 threshold level of table size for direct reads



以上數據庫中,200正好約為Buffer數量的2%:

SQL> show parameter db_cache_size

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_cache_size big integer 83886080
SQL> select (83886080/8192)*2/100 from dual;

(83886080/8192)*2/100
---------------------
204.8


所以要區分大小表(Long/Short)是因為全表掃描可能引起Buffer Cache的抖動,缺省的大表的全表掃描會被置於LRU的末端,以期盡快老化,減少Buffer的占用。從Oracle8i開始,Oracle的多緩沖池管理技術(Default/Keep/Recycle池)給了我們另外一個選擇,對於不同大小、不同使用頻率的數據表,從建表之初就可以指定其存儲Buffer,以使得內存使用更加有效。

 

有時一個查詢結果需要從兩個或兩個以上表中提取字段數據,此時需要使用多表關聯查詢。

 1)笛卡爾積關聯

  create table a(
   id number(7),
   name varchar2(20));

  create table b(
   id number(7),
   name varchar2(20));

  insert into a(id,name) values(1,'a1');
  insert into a(id,name) values(2,'a2');
  insert into a(id,name) values(3,'a3');
  insert into b(id,name) values(1,'b1');
  insert into b(id,name) values(2,'b2');

 select * from a,b;

 笛卡爾積特點:
   --*代表from后面表中所有列
   --返回結果數量是各個表記錄的乘積
   --結果是a每條記錄與b每條記錄結合形成

 *2)等值連接
  參與等值條件的兩個字段值,相等時才作為結果返回。
 select a.id,a.name,b.name //3.提取顯示的字段
 from a,b //1.形成笛卡爾積結果
 where a.id=b.id; //2.返回id相等的記錄

  ---使用[INNER] JOIN...ON...語法-----
 select a.id,a.name,b.name
 from a join b on(a.id=b.id);

 提示:建議采用JOIN...ON語法,INNER JOIN和JOIN作用等價。內連接,等值連接是一個意思。
   
  ----使用JOIN...USING語法(了解)------
 select id,a.name,b.name
 from a join b using(id);

JOIN...USING使用注意事項:
 --關聯的兩個表中需要有相同的字段.(名字和類型相同)
 --關聯的字段在使用時不能加別名

  //查詢員工名稱,工資,所在部門編號,部門名稱
  select e.ename,e.sal,e.deptno,d.dname
  from emp e join dept d 
     on(e.deptno=d.deptno);

3)外連接
  等值連接,需要兩個表的關聯字段等值才將結果返回。如果需要將某一個表記錄全部返回,即使
  另一個表找不到對等字段記錄,此時可以使用外連接。
  *a.左外連接

  ----使用LEFT OUTER JOIN...ON...語法------
  select e.ename,e.sal,e.deptno,d.dname
  from emp e left outer join dept d 
     on(e.deptno=d.deptno);
    
 A left outer join B on(...)
 以A表記錄顯示為主,B表記錄為補充.當A表記錄在B表找不到對等記錄時,B以NULL方式補充。

  b.右外連接
 select e.ename,e.sal,e.deptno,d.dname
  from emp e right outer join dept d 
     on(e.deptno=d.deptno);
 上面語句是以dept表顯示為主,emp為補充.如果emp沒有對等記錄,字段值以NULL補充。

select * from a 
 right outer join b on(a.id=b.id);
等價於
select * from b 
 left outer join a on(a.id=b.id)

----在JOIN...ON之前的外連接寫法--------
//(+)所在表為補充表,另一方是主表
select * from a,b
where a.id(+)=b.id; //jb為主,ja為補充

  c.全外連接
   全外連接=左外連接+右外鏈接-(重復記錄)
  select * from a 
    full outer join b on(a.id=b.id);

 //查詢部門編號,部門名稱,部門員工人數
  select d.deptno,
         d.dname,
         count(e.ename) num
  from DEPT d left outer join EMP e 
    on(d.deptno=e.deptno)
  group by d.deptno,d.dname
  order by d.deptno;


EMPNO ENAME DEPTNO DNAME
...    ...    10   ...
NULL   NULL   40   ...
NULL   NULL   50   ...
//按部門分組統計,count(*)和count(ename)的區別
count(*) = 1 
count(ename) = 0

//查詢部門在NEW YORK和CHICAGO的員工編號和員工名稱
select e.empno,e.ename
from DEPT d join EMP e on(d.deptno=e.deptno)
where d.loc in ('NEW YORK','CHICAGO');

4)自連接
  關聯雙方的表是同一個表。

  //查詢員工編號,員工名,上級編號,上級名稱
  select e.empno,e.ename,e.mgr,e1.ename
  from EMP e left outer join 
       EMP e1 on(e.mgr=e1.empno);
  //查詢員工編號,員工名,所在部門名,上級編號,上級名稱
  select e.empno,e.ename,d.dname,e.mgr,e1.ename
  from EMP e 
     left outer join EMP e1 on(e.mgr=e1.empno)
     left outer join DEPT d on(d.deptno=e.deptno);
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM