中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

唯一性索引(Unique Index)與普通索引(Normal Index)差異(上)

發布時間:2020-08-11 20:04:13 來源:ITPUB博客 閱讀:266 作者:leodinas_kong 欄目:建站服務器

 

索引是我們經常使用的一種數據庫搜索優化手段。適當的業務操作場景使用適當的索引方案可以顯著的提升系統整體性能和用戶體驗。在Oracle中,索引有包括很多類型。不同類型的索引適應不同的系統環境和訪問場景。其中,唯一性索引Unique Index是我們經常使用到的一種。

 

唯一性索引unique index和一般索引normal index最大的差異就是在索引列上增加了一層唯一約束。添加唯一性索引的數據列可以為空,但是只要存在數據值,就必須是唯一的。

 

那么,在使用唯一性索引時,同一般索引有什么差異呢?下面通過一系列的演示實驗來說明。

 

1、實驗環境準備

 

為了體現出一致性和可能的差異性,選擇相同的數據值列加入不同類型的索引結構。

 

 

SQL> select * from v$version where rownum<2;

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

 

SQL> create table t as select * from dba_objects;

Table created

 

//保證data_object_idobject_id取值相同;

SQL> update t set data_object_id=object_id;

72581 rows updated

 

SQL> commit;

Commit complete

 

//普通索引

SQL> create index idx_t_normalid on t(object_id);

Index created

 

//唯一性索引

SQL> create unique index idx_t_uniid on t(data_object_id);

Index created

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

 

 

 

2、體積容量比較

 

在環境準備中,我們將索引列取值設置為完全相同,盡量避免由于外在原因引起的差異。下面我們檢查數據字典中的容量比較信息。

 

首先是查看索引段index segment信息。

 

 

SQL> select segment_name, segment_type, bytes, blocks, extents from dba_segments where segment_name in ('IDX_T_NORMALID','IDX_T_UNIID');

 

SEGMENT_NAME         SEGMENT_TYPE         BYTES     BLOCKS  EXTENTS

-------------------- ------------------ ---------- ---------- ----------

IDX_T_NORMALID       INDEX                  983040        120         15

IDX_T_UNIID            INDEX                  917504        112         14

 

 

一般索引normal index較唯一性索引空間消耗略大。索引idx_t_normalid占據15個分區,120block。略大于idx_t_uniid14個分區塊。

 

這個地方需要注意一下,在數據字典中一個segment的分區占據,是Oracle系統分配給的空間,并不意味著全部使用殆盡。可能兩個索引結構差異很小,但是額外多分配出一個extent

 

索引葉子結構上,檢查數據字典內容。

 

 

SQL> select index_name, index_type, UNIQUENESS, BLEVEL, LEAF_BLOCKS, DISTINCT_KEYS from dba_indexes where index_name in ('IDX_T_NORMALID','IDX_T_UNIID');

 

INDEX_NAME           INDEX_TYPE      UNIQUENESS     BLEVEL LEAF_BLOCKS DISTINCT_KEYS

-------------------- --------------- ---------- ---------- ----------- -------------

IDX_T_UNIID          NORMAL          UNIQUE              1         106         51330

IDX_T_NORMALID       NORMAL          NONUNIQUE           1         113         51330

 

 

兩者的差異不大,normal index空間消耗要略大于unique index

 

結論:從數據字典反映出的情況可以知道,同一般索引相比,唯一性索引的空間消耗略小一些。由于我們采用的實驗數據都是相同的,這一點點的差距可能就意味著兩種索引類型在存儲結構上存在略微的差異。

 

 

3、違反約束實驗

 

作為唯一性索引,在添加創建和進行dml操作的時候,都會嚴格發揮出約束的作用。

 

SQL> insert into t select * from t where rownum<2;

 

insert into t select * from t where rownum<2

 

ORA-00001: 違反唯一約束條件 (SYS.IDX_T_UNIID)

 

 

 

4、等號檢索實驗

 

當我們進行等號查詢的時候,Oracle對兩種索引生成的執行計劃有何種差異?注意:下面的select檢索之前,都使用flush語句對shared_poolbuffer_cache進行清理。

 

 

--精確查詢

SQL> select * from t where object_id=1000;

執行計劃

----------------------------------------------------------

Plan hash value: 776407697

----------------------------------------------------------------------------------------------

| Id  | Operation                   | Name           | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                |     1 |   101 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T              |     1 |   101 |     2   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_T_NORMALID |     1 |       |     1   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("OBJECT_ID"=1000)

統計信息

----------------------------------------------------------

        528  recursive calls

          0  db block gets

         87  consistent gets

         11  physical reads

          0  redo size

       1200  bytes sent via SQL*Net to client

        376  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          4  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

SQL> select * from t where data_object_id=1000;

 

執行計劃

----------------------------------------------------------

Plan hash value: 335537167

 

-------------------------------------------------------------------------------------------

| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |             |     1 |   101 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T           |     1 |   101 |     2   (0)| 00:00:01 |

|*  2 |   INDEX UNIQUE SCAN         | IDX_T_UNIID |     1 |       |     1   (0)| 00:00:01 |

-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("DATA_OBJECT_ID"=1000)

統計信息

----------------------------------------------------------

        528  recursive calls

          0  db block gets

         86  consistent gets

         10  physical reads

          0  redo size

       1200  bytes sent via SQL*Net to client

        376  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          4  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

 

這里,我們看到了Unique Index的一個特性,就是等號操作時執行計劃的差異。對Unique Index而言,進行相等查詢的結果只有一行值或者沒有,所以沒必要進行傳統的Index Range Scan操作。此處,執行計劃中使用的是Index Unique Scan操作,直接精確定位到指定的記錄項目,返回rowid記錄。

 

而一般索引在進行等號檢索的時候,通常使用的就是Index Range Scan操作。沿著索引樹葉子節點進行水平掃描操作,直到獲取索引符合條件索引列值的rowid列表。

 

從成本上看,兩者雖然執行計劃操作方式有一定差別,但是成本實際差異不大。CPU成本和執行時間上相同。各種塊讀操作(邏輯讀和物理讀)存在一些差異,筆者認為源于兩個索引結構的微量區別,這樣讀取的塊數一定有些差異。

 

 

5、范圍搜索實驗

 

當我們進行索引列的范圍搜索時,執行計劃和成本有何種差異呢?

 

 

--范圍匹配

SQL> select * from t where object_id>=1000 and object_id<=1500;

已選擇490行。

 

執行計劃

----------------------------------------------------------

Plan hash value: 776407697

----------------------------------------------------------------------------------------------

| Id  | Operation                   | Name           | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                |   485 | 48985 |    14   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T              |   485 | 48985 |    14   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_T_NORMALID |   485 |       |     3   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("OBJECT_ID">=1000 AND "OBJECT_ID"<=1500)

 

統計信息

----------------------------------------------------------

        528  recursive calls

          0  db block gets

        158  consistent gets

         17  physical reads

          0  redo size

      23775  bytes sent via SQL*Net to client

        728  bytes received via SQL*Net from client

         34  SQL*Net roundtrips to/from client

          4  sorts (memory)

          0  sorts (disk)

        490  rows processed

 

 

SQL> select * from t where data_object_id>=1000 and data_object_id<=1500;

已選擇490行。

 

執行計劃

----------------------------------------------------------

Plan hash value: 2700411221

 

-------------------------------------------------------------------------------------------

| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |             |   485 | 48985 |    14   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T           |   485 | 48985 |    14   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_T_UNIID |   485 |       |     3   (0)| 00:00:01 |

-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("DATA_OBJECT_ID">=1000 AND "DATA_OBJECT_ID"<=1500)

 

統計信息

----------------------------------------------------------

        528  recursive calls

          0  db block gets

        157  consistent gets

         16  physical reads

          0  redo size

      23775  bytes sent via SQL*Net to client

        728  bytes received via SQL*Net from client

         34  SQL*Net roundtrips to/from client

          4  sorts (memory)

          0  sorts (disk)

        490  rows processed

 

 

 

從實驗結果看,兩者在進行范圍搜索時,執行計劃沒有差異。兩者都是進行Index Range Scan操作。各類型成本基本相同。

 

 

6、結論

 

本篇主要從應用角度,分析Unique Index與一般normal Index的差異。從結果看,Unique Index就是額外添加的唯一性約束。該約束嚴格的保證索引列的取值唯一性,這在一些數據列上的業務約束實現是很重要的功能。比如一個數據列,不能作為主鍵,而且允許為空,但是業務上要求唯一特性。這時候使用唯一性索引就是最好的選擇。

 

從執行計劃where條件中的表現看,Unique Index和一般normal Index沒有顯著性的差異。

 

 

兩者數據基礎值一樣的情況下,生成索引的體積存在略微的差異,說明在存儲結構上兩者可能有不同。下面我們來分析一下兩類型索引的結構信息。

 

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

建湖县| 德清县| 汉源县| 郯城县| 清水河县| 阜宁县| 获嘉县| 阆中市| 铜山县| 张家界市| 邢台市| 花莲县| 东平县| 巴彦县| 县级市| 长丰县| 子长县| 泰顺县| 安丘市| 娄底市| 卫辉市| 承德县| 光山县| 惠来县| 灵川县| 昭平县| 松江区| 临城县| 泰和县| 漳州市| 枣庄市| 灵川县| 习水县| 巴马| 互助| 巴林左旗| 水富县| 横峰县| 鄂尔多斯市| 中方县| 桑日县|