日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Oracle-index索引解读

發布時間:2025/3/21 编程问答 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Oracle-index索引解读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

Oracle-OLAP和OLTP解讀

Oracle-index索引解讀

Oracle-分區表解讀

Oracle-鎖解讀

Oracle-等待事件解讀

Oracle-procedure/cursor解讀




  • 索引是數據庫對象之一,用于加快數據的檢索

  • 索引是建立在表上的可選對象;索引的關鍵在于通過一組排序后的索引鍵來取代默認的全表掃描檢索方式,索引直接指向包含所查詢值的行的位置,減少磁盤I/O,,從而提高檢索效率

  • 索引在邏輯上和物理上都與相關的表和數據無關,當創建或者刪除一個索引時,不會影響基本的表,與所索引的表是相互獨立的物理結構

  • 索引一旦建立,Oracle 自動使用并維護索引,插入、刪除、更新表后,自動更新索引,不會對表產生影響.

  • 索引對用戶是透明的,無論表上是否有索引,sql語句的用法不變

  • oracle創建主鍵時會自動在該列上創建索引


為什么需要索引

數據在磁盤上是以塊的形式存儲的。為確保對磁盤操作的原子性,訪問數據的時候會一并訪問所有數據塊。磁盤上的這些數據塊與鏈表類似,即它們都包含一個數據段和一個指針,指針指向下一個節點(數據塊)的內存地址,而且它們都不需要連續存儲(即邏輯上相鄰的數據塊在物理上可以相隔很遠)。

鑒于很多記錄只能做到按一個字段排序,所以要查詢某個未經排序的字段,就需要使用線性查找,即要訪問N/2個數據塊,其中N指的是一個表所涵蓋的所有數據塊。如果該字段是非鍵字段(也就是說,不包含唯一值),那么就要搜索整個表空間,即要訪問全部N個數據塊。

然而,對于經過排序的字段,可以使用二分查找,因此只要訪問log2 N個數據塊。同樣,對于已經排過序的非鍵字段,只要找到更大的值,也就不用再搜索表中的其他數據塊了。這樣一來,性能就會有實質性的提升。


什么是索引

索引是對記錄按照多個字段進行排序的一種方式。對表中的某個字段建立索引會創建另一種數據結構,其中保存著字段的值,每個值又指向與它相關的記錄。這種索引的數據結構是經過排序的,因而可以對其執行二分查找。

索引的缺點是占用額外的磁盤空間。所以如果為同一個表中的很多字段都建立索引,那這個文件可能會很快膨脹到文件系統規定的上限。

當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。


索引的原理

首先,來看一個示例數據庫表的模式:

注意:這里用char而不用varchar是為了精確地描述數據占用磁盤的大小。

這個示例數據庫中包含500萬行記錄,而且沒有建立索引。

接下來我們就分析針對這個表的兩個查詢:一個查詢使用id(經過排序的鍵字段),另一個查詢使用firstName(未經排序的非鍵字段)。

示例分析一

對于這個擁有r = 5 000 000條記錄的示例數據庫,在磁盤上要為每條記錄分配 R = (4+50+50+100)204字節的固定存儲空間(4個字段所占空間的總和)。


默認的數據庫塊大小為 B = 1024字節。于是,我們可計算出這個表的分塊因數為 bfr = (B/R) = 1024/204 = 5,即磁盤上每個數據塊保存5條記錄。那么,保存整個表所需的數據塊數就是 N = (r/bfr) = 5000000/5 = 1 000 000。


使用線性查找搜索id字段——這個字段是鍵字段(每個字段的值唯一),需要訪問 N/2 = 500 000個數據塊才能找到目標值。不過,因為這個字段是經過排序的,所以可以使用二分查找法,而這樣平均只需要訪問log2(1000000 )= 19.93 = 20 個塊。顯然,這會給性能帶來極大的提升。


再來看看firstName字段,這個字段是未經排序的,因此不可能使用二分查找,況且這個字段的值也不是唯一的,所以要從表的開頭查找末尾,即要訪問 N = 1 000 000個數據塊。這種情況通過建立索引就能得到改善。


如果一條索引記錄只包含索引字段和一個指向原始記錄的指針,那么這條記錄肯定要比它所指向的包含更多字段的記錄更小。也就是說,索引本身占用的磁盤空間比原來的表更少,因此需要遍歷的數據塊數也比搜索原來的表更少。

以下是firstName字段索引的模式:

示例分析二

對于這個擁有r = 5 000 000條記錄的示例數據庫,每條索引記錄要占用 R = 54字節磁盤空間,而且同樣使用默認的數據塊大小 B = 1024字節。那么索引的分塊因數就是 bfr = (B/R) = 1024/54 = 18。最終這個表的索引需要占用 N = (r/bfr) = 5000000/18 = 277 778個數據塊。


現在,再搜索firstName字段就可以使用索引來提高性能了。對索引使用二分查找,需要訪問 log2 277778 = 18.09 = 19個數據塊。再加上為找到實際記錄的地址還要訪問一個數據塊,總共要訪問 19 + 1 = 20個數據塊,這與搜索未索引的表需要訪問277 778個數據塊相比,不啻于天壤之別。


什么時候用索引

創建索引要額外占用磁盤空間(比如,上面例子中要額外占用277 778個數據塊),建立的索引太多可能導致磁盤空間不足。因此,在建立索引時,一定要慎重選擇正確的字段。

由于索引只能提高搜索記錄中某個匹配字段的速度,因此在執行插入和刪除操作的情況下,僅為輸出結果而為字段建立索引,就純粹是浪費磁盤空間和處理時間了;這種情況下不用建立索引

另外,由于二分查找的原因,數據的基數性(cardinality)或唯一性也非常重要。對基數性為2的字段建立索引,會將數據一分為二,而對基數性為1000的字段,則同樣會返回大約1000條記錄。在這么低的基數性下,索引的效率將減低至線性查找的水平,而查詢優化器會在基數性小于記錄數的30%時放棄索引,實際上等于索引純粹只會浪費空間。

另外需要說明: 創建了索引并不一定就會使用,oracle自動統計表的信息后,決定是否使用索引,表中數據很少時使用全表掃描速度已經很快,沒有必要使用索引


索引的語法

創建索引

CREATE UNIUQE | BITMAP INDEX <schema>.<index_name>ON <schema>.<table_name>(<column_name> | <expression> ASC | DESC,<column_name> | <expression> ASC | DESC,...)TABLESPACE <tablespace_name>STORAGE <storage_settings>LOGGING | NOLOGGINGCOMPUTE STATISTICSNOCOMPRESS | COMPRESS<nn>NOSORT | REVERSEPARTITION | GLOBAL PARTITION<partition_setting>

參數說明:

  • 1) UNIQUE | BITMAP:指定UNIQUE為唯一值索引,BITMAP為位圖索引,省略為B-Tree索引。

  • 2)<column_name> | <expression> ASC |
    DESC:可以對多列進行聯合索引,當為expression時即“基于函數的索引”

  • 3)TABLESPACE:指定存放索引的表空間(索引和原表不在一個表空間時效率更高)

  • 4)STORAGE:可進一步設置表空間的存儲參數

  • 5)LOGGING | NOLOGGING:是否對索引產生重做日志(對大表盡量使用NOLOGGING來減少占用空間并提高效率)

  • 6)COMPUTE STATISTICS:創建新索引時收集統計信息

  • 7)NOCOMPRESS | COMPRESS<nn>:是否使用“鍵壓縮”(使用鍵壓縮可以刪除一個鍵列中出現的重復值)

  • 8)NOSORT | REVERSE:NOSORT表示與表中相同的順序創建索引,REVERSE表示相反順序存儲索引值

  • 9)PARTITION | NOPARTITION:可以在分區表和未分區表上對創建的索引進行分區

修改索引

重命名索引

alter index index_sno rename to bitmap_index;

合并索引

表使用一段時間后在索引中會產生碎片,此時索引效率會降低,可以選擇重建索引或者合并索引,合并索引方式更好些,無需額外存儲空間,代價較低

alter index index_sno coalesce;

重建索引

方式一:刪除原來的索引,重新建立索引

方式二:使用rebuild方式

alter index index_sno rebuild [online];

rebuild 和 rebuild online的區別

alter index rebuild online:實質上是掃描表而不是掃描現有的索引塊來實現索引的重建

alter index rebuild:只掃描現有的索引塊來實現索引的重建。

rebuild index online在執行期間不會阻塞DML操作,但在開始和結束階段,需要請求模式為4的TM鎖。因此,如果在rebuild index online開始前或結束時,有其它長時間的事物在運行,很有可能就造成大量的鎖等待。也就是說在執行前仍會產生阻塞, 應該避免排他鎖.

而rebuild index在執行期間會阻塞DML操作, 但速度較快.

兩者重建索引時的掃描方式不同,
rebuild用的是“INDEX FAST FULL SCAN”,
rebuild online用的是“TABLE ACCESS FULL”;
即rebuild index是掃描索引塊,而rebuild index online是掃描全表的數據塊.

刪除索引

drop index index_sno;

查看索引

查詢all_indexes select index_name, index_type, tablespace_name, uniquenessfrom all_indexeswhere table_name = 'tablename';或者查詢user_indexes select a.* from user_indexes a ;

B樹索引的index_type為 NORMAL;而位圖索引的index_type類型值為BITMAP

索引分類

  • B-樹索引(默認類型)
  • 位圖索引
  • HASH索引
  • 索引編排表
  • 反轉鍵索引
  • 基于函數的索引
  • 分區索引
  • 本地和全局索引

B樹索引

說明

B樹索引在Oracle中是一個通用索引。在創建索引時它就是默認的索引類型。B樹索引可以是一個列的(簡單)索引,也可以是組合/復合(多個列)的索引。

B樹索引最多可以包括32列。

特點

1.oracle中最常用的索引;B樹索引就是一顆二叉樹;葉子節點(雙向鏈表)包含索引列和指向表中每個匹配行的ROWID值

2.所有葉子節點具有相同的深度,因而不管查詢條件怎樣,查詢速度基本相同

3.能夠適應精確查詢、模糊查詢和比較查詢

創建

B樹索引的單一索引

單一索引:

Create Index <Index-Name> On <Table_Name>(Column_Name)

B樹索引的 復合索引

復合索引:

Create Index i_deptno_job on emp(deptno,job); —>在emp表的deptno、job列建立索引。  select * from emp where deptno=66 and job='sals' ->走索引。select * from emp where deptno=66 OR job='sals' ->將進行全表掃描。不走索引select * from emp where deptno=66 ->走索引。select * from emp where job='sals' ->進行全表掃描、不走索引。

  如果在where 子句中有OR 操作符或單獨引用Job 列(索引列的后面列) 則將不會走索引,將會進行全表掃描。
  
 即如果索引建立在多個列上,只有它的第一個列被where子句引用時,優化器才會使用該索引,即至少要包含組合索引的第一列

適合使用場景

  • 適合與大量的增、刪、改(OLTP)
  • 不能用包含OR操作符的查詢;
  • 列基數(列不重復值的個數)大時適合使用B數索引

位圖索引

說明

創建位圖索引時,oracle會掃描整張表,并為索引列的每個取值建立一個位圖(位圖中,對表中每一行使用一位(bit,0或者1)來標識該行是否包含該位圖的索引列的取值,如果為1,表示對應的rowid所在的記錄包含該位圖索引列值),最后通過位圖索引中的映射函數完成位到行的ROWID的轉換.

位圖索引非常適合于決策支持系統(Decision Support System,DSS)和數據倉庫,它們不應該用于通過事務處理應用程序訪問的表。

它們可以使用較少到中等基數(不同值的數量)的列訪問非常大的表。
盡管位圖索引最多可達30個列,但通常它們都只用于少量的列。

比如:某個表可能包含一個稱為Sex的列,它有兩個可能值:男和女。這個基數只為2,如果用戶頻繁地根據Sex列的值查詢該表,這就是位圖索引的基列。當一個表內包含了多個位圖索引時,您可以體會到位圖索引的真正威力。如果有多個可用的位圖索引,Oracle就可以合并從每個位圖索引得到的結果集,快速刪除不必要的數據。

特點

  • 適合與決策支持系統;
  • 做UPDATE代價非常高;
  • 非常適合OR操作符的查詢;
  • 基數比較少的時候才能建位圖索引;

創建

例子:

Create bitmap Index <Index-Name> On <Table_Name>(Column_Name)

適合使用場景

  • 對于基數小的列適合建立位圖索引(例如性別等)

注意事項

  • 建議不要在一些聯機事務處理(OLTP)應用程序中使用位圖索引。位圖索引的索引值中包含ROWID,這樣Oracle就可以在行級別上鎖定索引。

    位圖索引存儲為壓縮的索引值,其中包含了一定范圍的ROWID,因此Oracle必須針對一個給定值鎖定所有范圍內的ROWID。這種鎖定類型可能在某些DML語句中造成死鎖。

    SELECT語句不會受到這種鎖定問題的影響。

  • 基于規則的優化器不會考慮位圖索引。

  • 當執行ALTER TABLE語句并修改包含有位圖索引的列時,會使位圖索引失效。
  • 位圖索引不包含任何列數據,并且不能用于任何類型的完整性檢查。
  • 位圖索引不能被聲明為唯一索引。
  • 位圖索引的最大長度為30。

函數索引

說明

  • 當經常要訪問一些函數或者表達式時,可以將其存儲在索引中,這樣下次訪問時,該值已經計算出來了,可以加快查詢速度

  • 函數索引既可以使用B樹索引,也可以使用位圖索引;當函數結果不確定時采用B樹索引,結果是固定的某幾個值時使用位圖索引

  • 函數索引中可以使用len、trim、substr、upper(每行返回獨立結果),不能使用如sum、max、min、avg等

  • 基于函數的索引非常有用,但在實現時必須小心。在表上創建的索引越多,INSERT、UPDATE和DELETE語句的執行就會花費越多的時間。

創建

例子:

CREATE INDEX index ON table (FUNCTION(column));舉例: select * from student where upper(name) ='XGJ';

分區索引

分區索引就是簡單地把一個索引分成多個片斷。通過把一個索引分成多個片斷,可以訪問更小的片斷(也更快),并且可以把這些片斷分別存放在不同的磁盤驅動器上(避免I/O問題)。

B樹和位圖索引都可以被分區,而HASH索引不可以被分區。

可以有好幾種分區方法:表被分區而索引未被分區;表未被分區而索引被分區;表和索引都被分區。

不管采用哪種方法,都必須使用基于成本的優化器。分區能夠提供更多可以提高性能和可維護性的可能性

有兩種類型的分區索引:本地分區索引和全局分區索引。

每個類型都有兩個子類型,有前綴索引和無前綴索引。表各列上的索引可以有各種類型索引的組合。如果使用了位圖索引,就必須是本地索引。

把索引分區最主要的原因是可以減少所需讀取的索引的大小,另外把分區放在不同的表空間中可以提高分區的可用性和可靠性。

在使用分區后的表和索引時,Oracle還支持并行查詢和并行DML。這樣就可以同時執行多個進程,從而加快處理這條語句。


創建索引的一些規則

1. 權衡索引個數與DML之間關系,DML也就是插入、刪除數據操作。
這里需要權衡一個問題,建立索引的目的是為了提高查詢效率的,但建立的索引過多,會影響插入、刪除數據的速度,因為我們修改的表數據,索引也要跟著修改。這里需要權衡我們的操作是查詢多還是修改多。

2. 把索引與對應的表放在不同的表空間。
當讀取一個表時表與索引是同時進行的。如果表與索引和在一個表空間里就會產生資源競爭,放在兩個表這空就可并行執行。

3. 最好使用一樣大小的塊。
Oracle默認五塊,讀一次I/O,如果你定義6個塊或10個塊都需要讀取兩次I/O。最好是5的整數倍更能提高效率。

4. 如果一個表很大,建立索引的時間很長,因為建立索引也會產生大量的redo信息,所以在創建索引時可以設置不產生或少產生redo信息。只要表數據存在,索引失敗了大不了再建,所以可以不需要產生redo信息。

5. 建索引的時候應該根據具體的業務SQL來創建,特別是where條件,還有where條件的順序,盡量將過濾大范圍的放在后面,因為SQL執行是從后往前的。

索引應該經常建在Where 子句經常用到的列上。如果某個大表經常使用某個字段進行查詢,并且檢索行數小于總表行數的5%。則應該考慮。

6. 如果有兩個或者以上的索引,其中有一個唯一性索引,而其他是非唯一,這種情況下oracle將使用唯一性索引而完全忽略非唯一性索引

7. 至少要包含組合索引的第一列(即如果索引建立在多個列上,只有它的第一個列被where子句引用時,優化器才會使用該索引)

8. 小表不要建立索引

9. 對于基數大的列適合建立B樹索引,對于基數小的列適合建立位圖索引

10. 列中有很多空值,但經常查詢該列上非空記錄時應該建立索引

11. 經常進行連接查詢的列應該創建索引

12. 使用create index時要將最常查詢的列放在最前面

13. LONG(可變長字符串數據,最長2G)和LONG RAW(可變長二進制數據,最長2G)列不能創建索引

14. 限制表中索引的數量(創建索引耗費時間,并且隨數據量的增大而增大;索引會占用物理空間;當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,降低了數據的維護速度)

15 .對于兩表連接的字段,應該建立索引。如果經常在某表的一個字段進行Order By 則也應該建立索引。


索引失效的情況

1.使用不等于操作符(not 、<>、!=)

oracle碰到not或者 <> !=會停止使用索引,而采用全表掃描

select * from student where not (score=100);select * from student where score <> 100;--替換為select * from student where score>100 or score <100

通過把不等于操作符改成OR條件,就可以使用索引,以避免全表掃描。

2. 使用IS NULL 或IS NOT NULL

使用IS NULL 或IS NOT NULL同樣會限制索引的使用。
因為NULL值并沒有被定義。在SQL語句中使用NULL會有很多的麻煩。因此建議開發人員在建表時,把需要索引的列設成 NOT NULL。
如果被索引的列在某些行中存在NULL值,就不會使用這個索引(除非索引是一個位圖索引)。

select * from student where score is not null;

索引上使用空值比較將停止使用索引.

3.使用函數

如果不使用基于函數的索引,那么在SQL語句的WHERE子句中對存在索引的列使用函數時,會使優化器忽略掉這些索引。 下面的查詢不會使用索引(只要它不是基于函數的索引)

select empno,ename,deptno from emp where trunc(hiredate)='01-MAY-81';--把上面的語句改成下面的語句,這樣就可以通過索引進行查找。 select empno,ename,deptno from emp where hiredate<(to_date('01-MAY-81')+0.9999);

4.索引列上進行計算

索引列上不能進行計算

SELECT Col FROM tbl WHERE col / 10 > 10

則會使索引失效,應該改成

SELECT Col FROM tbl WHERE col > 10 * 10

5.比較不匹配的數據類型

假設account_number是一個VARCHAR2類型,在account_number字段上有索引。
下面的語句將執行全表掃描:

select bank_name,address,city,state,zip from banks where account_number = 990354;

Oracle可以自動把where子句變成to_number(account_number)=990354,這樣就限制了索引的使用。

改成下面的查詢就可以使用索引:

select bank_name,address,city,state,zip from banks where account_number ='990354';

特別注意:不匹配的數據類型之間比較會讓Oracle自動限制索引的使用,即便對這個查詢執行Explain Plan也不能讓您明白為什么做了一次“全表掃描”。

6.通配符在搜索詞首出現時,oracle不能使用索引

--我們在name上創建索引;create index index_name on student('name');--下面的方式oracle不適用name索引select * from student where name like '%xgj%';--如果通配符出現在字符串的其他位置時,優化器能夠利用索引;如下:select * from student where name like 'xgj%';

7.用UNION替換OR(適用于索引列)

union:是將兩個查詢的結果集進行追加在一起,它不會引起列的變化。

由于是追加操作,需要兩個結果集的列數應該是相關的,并且相應列的數據類型也應該相當的。

union 返回兩個結果集,同時將兩個結果集重復的項進行消除。

如果不進行消除,用UNOIN ALL.

通常情況下, 用UNION替換WHERE子句中的OR將會起到較好的效果. 對索引列使用OR將造成全表掃描. 注意, 以上規則只針對多個索引列有效.

如果有column沒有被索引, 查詢效率可能會因為你沒有選擇OR而降低.

在下面的例子中, LOC_ID 和REGION上都建有索引.

  高效:

  SELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE LOC_ID = 10UNIONSELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE REGION = “MELBOURNE”

  低效:
 

 SELECT LOC_ID , LOC_DESC , REGIONFROM LOCATIONWHERE LOC_ID = 10 OR REGION = “MELBOURNE”

  如果你堅持要用OR, 那就需要返回記錄最少的索引列寫在最前面.

8. 用EXISTS替代IN、用NOT EXISTS替代NOT IN

在許多基于基礎表的查詢中, 為了滿足一個條件, 往往需要對另一個表進行聯接. 在這種情況下, 使用EXISTS(或NOT EXISTS)通常將提高查詢的效率.

在子查詢中, NOT IN子句將執行一個內部的排序和合并.

無論在哪種情況下, NOT IN都是最低效的(因為它對子查詢中的表執行了一個全表遍歷).

為了避免使用NOT IN, 我們可以把它改寫成外連接(Outer Joins)或NOT EXISTS.

例子:

高效:

SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB’)

低效:

SELECT * FROM EMP (基礎表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB’)

Sql優化的一點建議

Sql 優化:

當Oracle數據庫拿到SQL語句時,其會根據查詢優化器分析該語句,并根據分析結果生成查詢執行計劃。
也就是說,數據庫是執行的查詢計劃,而不是Sql語句。

查詢優化器有rule-based-optimizer(基于規則的查詢優化器) 和Cost-Based-optimizer(基于成本的查詢優化器)。

其中基于規則的查詢優化器在10g版本中消失。

對于規則查詢,其最后查詢的是全表掃描。而CBO則會根據統計信息進行最后的選擇。

  • 1、先執行From ->Where ->Group By->Order By

  • 2、執行From 字句是從右往左進行執行。因此必須選擇記錄條數最少的表放在右邊。

  • 3、對于Where字句其執行順序是從后向前執行、因此可以過濾最大數量記錄的條件必須寫在Where子句的末尾,而對于多表之間的連接,則寫在之前。
    因為這樣進行連接時,可以去掉大多不重復的項。

  • 4、SELECT子句中避免使用(*)ORACLE在解析的過程中, 會將’*’ 依次轉換成所有的列名, 這個工作是通過查詢數據字典完成的,這意味著將耗費更多的時間

總結

以上是生活随笔為你收集整理的Oracle-index索引解读的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。