国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > Oracle > 正文

Oracle Index 三講

2024-08-29 13:39:09
字體:
來源:轉載
供稿:網友

  索引( Index )是常見的數據庫對象,它的設置好壞、使用是否得當,極大地影響數據庫應用程序和Database 的性能。雖然有許多資料講索引的用法, DBA 和 Developer 們也經常與它打交道,但筆者發現,還是有不少的人對它存在誤解,因此針對使用中的常見問題,講三個問題。 此文所有示例所用的數據庫是 Oracle 8.1.7 OPS on HP N series ,示例全部是真實數據,讀者不需要注重具體的數據大小,而應注重在使用不同的方法后,數據的比較。本文所講基本都是陳詞濫調,但是筆者試圖通過實際的例子,來真正讓您明白事情的要害。 
   
  一講,索引并非總是最佳選擇  
  假如發現Oracle 在有索引的情況下,沒有使用索引,這并不是Oracle 的優化器出錯。在有些情況下,Oracle 確實會選擇全表掃描(Full Table Scan),而非索引掃描(Index Scan)。這些情況通常有: 
  1, 表未做statistics, 或者 statistics 陳舊,導致 Oracle 判定失誤。 
  2, 根據該表擁有的記錄數和數據塊數,實際上全表掃描要比索引掃描更快。 
   
  對第1種情況,最常見的例子,是以下這句sql 語句: 
  select count(*) from mytable; 
  在未作statistics 之前,它使用全表掃描,需要讀取6000多個數據塊(一個數據塊是8k), 做了statistics 之后,使用的是 INDEX (FAST FULL SCAN) ,只需要讀取450個數據塊。但是,statistics 做得不好,也會導致Oracle 不使用索引。 
   
  第2種情況就要復雜得多。一般概念上都認為索引比表快,比較難以理解什么情況下全表掃描要比索引掃描快。為了講清楚這個問題,這里先介紹一下Oracle 在評估使用索引的代價(cost)時兩個重要的數據:CF(Clustering factor) 和 FF(Filtering factor). 
  CF: 所謂 CF, 通俗地講,就是每讀入一個索引塊,要對應讀入多少個數據塊。 
  FF: 所謂 FF, 就是該sql 語句所選擇的結果集,占總的數據量的百分比。 
  大約的計算公式是:FF * (CF + 索引塊個數) ,由此估計出,一個查詢, 假如使用某個索引,會需要讀入的數據塊塊數。需要讀入的數據塊越多,則 cost 越大,Oracle 也就越可能不選擇使用 index. (全表掃描需要讀入的數據塊數等于該表的實際數據塊數) 
  其核心就是, CF 可能會比實際的數據塊數量大。CF 受到索引中數據的排列方式影響,通常在索引剛建立時,索引中的記錄與表中的記錄有良好的對應關系,CF 都很小;在表經過大量的插入、修改后,這種對應關系越來越亂,CF 也越來越大。此時需要 DBA 重新建立或者組織該索引。 
  假如某個sql 語句以前一直使用某索引,較長時間后不再使用,一種可能就是 CF 已經變得太大,需要重新整理該索引了。 
  FF 則是Oracle 根據 statistics 所做的估計。比如, mytables 表有32萬行,其主鍵myid的最小值是1,最大值是409654,考慮以下sql 語句: 
  Select * from mytables where myid>=1; 和 
  Select * from mytables where myid>=400000 
  這兩句看似差不多的 sql 語句,對Oracle 而言,卻有巨大的差別。因為前者的 FF 是100%, 而后者的 FF 可能只有 1%。假如它的CF 大于實際的數據塊數,則Oracle 可能會選擇完全不同的優化方式。而實際上,在我們的數據庫上的測試驗證了我們的猜測. 以下是在HP 上執行時它們的 eXPlain plan: 
  第一句: 
  SQL> select * from mytables where myid>=1; 
   
  已選擇325917行。 
  Execution Plan 
  ---------------------------------------------------------- 
  0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3132 Card=318474 Byt es=141402456) 
  1 0 TABLE access (FULL) OF 'MYTABLES' (Cost=3132 Card=318474 Byt es=141402456) 
  Statistics 
  ---------------------------------------------------------- 
  7 recursive calls 
  89 db block gets 
  41473 consistent gets 
  19828 physical reads 
  0 redo size 
  131489563 bytes sent via SQL*Net to client 
  1760245 bytes received via SQL*Net from client 
  21729 SQL*Net roundtrips to/from client 
  1 sorts (memory) 
  0 sorts (disk) 
  325917 rows PRocessed 
   
  第二句: 
   
  Execution Plan 
  ---------------------------------------------------------- 
  0 SELECT STATEMENT Optimizer=CHOOSE (Cost=346 Card=663 Bytes=2 94372) 
  1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MYTABLES' (Cost=346 Card=663 
  Bytes=294372) 
  2 1 INDEX (RANGE SCAN) OF 'PK_MYTABLES' (UNIQUE) (Cost=5 Card=663) 
   
  Statistics 
  ---------------------------------------------------------- 
  1278 recursive calls 
  0 db block gets 
  6647 consistent gets 
  292 physical reads 
  0 redo size 
  3544898 bytes sent via SQL*Net to client 
  42640 bytes received via SQL*Net from client 
  524 SQL*Net roundtrips to/from client 
  1 sorts (memory) 
  0 sorts (disk) 
  7838 rows processed 
   
  顯而易見,第1句沒有使用索引,第2句使用了主鍵索引pk_mytables. FF的巨大影響由此可見一斑。
由此想到,我們在寫sql 語句時,假如預先估計一下 FF, 你就幾乎可以預見到 Oracle 會否使用索引。 
   
  二講,索引也有好壞  
  索引有 B tree 索引, Bitmap 索引, Reverse b tree 索引, 等。最常用的是 B tree 索引。 B 的全稱是Balanced , 其意義是,從 tree 的 root 到任何一個leaf ,要經過同樣多的 level. 索引可以只有一個字段(Single column), 也可以有多個字段(Composite),最多32個字段,8I 還支持 Function-based index. 許多developer 都傾向于使用單列B 樹索引。 
  所謂索引的好壞是指: 
  1,索引不是越多越好。非凡是大量從來或者幾乎不用的索引,對系統只有損害。OLTP系統每表超過5個索引即會降低性能,而且在一個sql 中, Oracle 從不能使用超過 5個索引。 
  2,很多時候,單列索引不如復合索引有效率。 
  3,用于多表連結的字段,加上索引會很有作用。 
  那么,在什么情況下單列索引不如復合索引有效率呢?有一種情況是顯而易見的,那就是,當sql 語句所查詢的列,全部都出現在復合索引中時,此時由于 Oracle 只需要查詢索引塊即可獲得所有數據,當然比使用多個單列索引要快得多。(此時,這種優化方式被稱為 Index only access path) 
  除此之外呢?我們還是來看一個例子吧: 
  在 HP(Oracle 8.1.7) 上執行以下語句: 
  select count(1) from mytabs where coid>=130000 and issuedate >= to_date ('2001-07-20', 'yyyy-mm-dd')。 
  一開始,我們有兩個單列索引:I_mytabs1(coid), I_mytabs2(issuedate), 下面是執行情況: 
   
  COUNT(1) 
  ---------- 
  6427 
   
  Execution Plan 
  ---------------------------------------------------------- 
  0 SELECT STATEMENT Optimizer=CHOOSE (Cost=384 Card=1 Bytes=11) 
  1 0 SORT (AGGREGATE) 
  2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T_MYTABS' (Cost=384 Card 
  =126 Bytes=1386) 
  3 2 INDEX (RANGE SCAN) OF 'I_MYTABS2' (NON-UNIQUE) (Cost=11 
  Card=126) 
   
  Statistics 
  ---------------------------------------------------------- 
  172 recursive calls 
  1 db block gets 
  5054 consistent gets 
  2206 physical reads 
  0 redo size 
  293 bytes sent via SQL*Net to client 
  359 bytes received via SQL*Net from client 
  2 SQL*Net roundtrips to/from client 
  5 sorts (memory) 
  0 sorts (disk) 
  1 rows processed 
  可以看到,它讀取了7000個數據塊來獲得所查詢的 6000多行。 
  現在,去掉這兩個單列索引,增加一個復合索引I_mytabs_test ( coid, issuedate), 重新執行,結果如下: 
  COUNT(1) 
  ---------- 
  6436 
   
  Execution Plan 
  ---------------------------------------------------------- 
  0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=11) 
  1 0 SORT (AGGREGATE) 
  2 1 INDEX (RANGE SCAN) OF 'I_MYTABS_TEST' (NON-UNIQUE) (Cost=3 Card=126 Bytes=1386) 
   
  Statistics 
  ---------------------------------------------------------- 
  806 recursive calls 
  5 db block gets 
  283 consistent gets 
  76 physical reads 
  0 redo size 
  293 bytes sent via SQL*Net to client 
  359 bytes received via SQL*Net from client 
  2 SQL*Net roundtrips to/from client 
  3 sorts (memory) 
  0 sorts (disk) 
  1 rows processed 
  可以看到,這次只讀取了300個數據塊。 
  7000塊對300塊,這就是在這個例子中,單列索引與復合索引的代價之比。這個例子提示我們, 在許多情況下,單列索引不如復合索引有效率。 
  可以說,在索引的設置問題上,其實有許多工作可以做。正確地

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 米脂县| 张家川| 新密市| 囊谦县| 阿克苏市| 清镇市| 冕宁县| 图片| 洛宁县| 原阳县| 平武县| 绥芬河市| 融水| 桂阳县| 连江县| 彭州市| 罗城| 雷州市| 二连浩特市| 东至县| 和静县| 南宁市| 鄯善县| 文昌市| 兴安盟| 盐山县| 华安县| 汾阳市| 年辖:市辖区| 彰武县| 赤峰市| 文昌市| 鹰潭市| 鹤山市| 荣昌县| 大方县| 南川市| 鄢陵县| 宜宾县| 武山县| 昭苏县|