B樹索引是Oracle默認索引,B樹索引能夠提升SQL語句的性能,強制執行主鍵和惟一鍵約束的惟一性,減小經過主鍵和外鍵約束關聯的父表和子表間潛在都鎖定問題。數據庫
create tablespace reporting_data datafile '+DATA/reporting_data01.dbf' size 1G extent management local uniform size 1M segment space management auto;
create tablespace reporting_index datafile '+DATA/reporting_index01.dbf' size 500M extent management local uniform size 128K segment space management auto nologging;
CREATE TABLE cust( cust_id NUMBER ,last_name VARCHAR2(30) ,first_name VARCHAR2(30)) TABLESPACE reporting_data;
create index cust_idx1 on cust(last_name) tablespace reporting_index online;
SQL> exec dbms_stats.gather_table_stats(ownname=>'testidx',tabname=>'CUST',cascade=>true); PL/SQL procedure successfully completed.
ALTER TABLE cust ADD CONSTRAINT cust_pk PRIMARY KEY (cust_id) USING INDEX TABLESPACE reporting_index;
ALTER TABLE cust ADD CONSTRAINT cust_uk1 UNIQUE (last_name, first_name) USING INDEX TABLESPACE reporting_index;
CREATE TABLE address( address_id NUMBER ,cust_id NUMBER ,street VARCHAR2(30) ,city VARCHAR2(30) ,state VARCHAR2(30)) TABLESPACE reporting_data;
ALTER TABLE address ADD CONSTRAINT addr_fk1 FOREIGN KEY (cust_id) REFERENCES cust(cust_id);
CREATE INDEX addr_fk1 ON address(cust_id) TABLESPACE reporting_index;
set linesize 300 col index_name for a30 col INDEX_TYPE for a10 col TABLE_NAME for a20 col TABLESPACE_NAME for a30 col status for a20 select index_name, index_type, table_name, tablespace_name, status from user_indexes where table_name in ('CUST','ADDRESS'); INDEX_NAME INDEX_TYPE TABLE_NAME TABLESPACE_NAME STATUS ------------------------------ ---------- ------------------------------ ----------------------------------------------------------- ------------------------ CUST_IDX1 NORMAL CUST REPORTING_INDEX VALID CUST_PK NORMAL CUST REPORTING_INDEX VALID CUST_UK1 NORMAL CUST REPORTING_INDEX VALID ADDR_FK1 NORMAL ADDRESS REPORTING_INDEX VALID
col index_name for a30 col column_name for a30 col column_position for 99999999999999 select index_name, column_name, column_position from user_ind_columns where table_name in ('CUST','ADDRESS') order by index_name, column_position; SQL> col index_name for a30 SQL> col column_name for a30 SQL> col column_position for 99999999999999 SQL> select index_name, column_name, column_position 2 from user_ind_columns 3 where table_name in ('CUST','ADDRESS') 4 order by index_name, column_position; INDEX_NAME COLUMN_NAME COLUMN_POSITION ------------------------------ ------------------------------ --------------- ADDR_FK1 CUST_ID 1 CUST_IDX1 LAST_NAME 1 CUST_PK CUST_ID 1 CUST_UK1 LAST_NAME 1 CUST_UK1 FIRST_NAME 2
col segment_name for a30 col segment_type for a30 col extents for 999999999999 col bytes for 999999999999 select a.segment_name, a.segment_type, a.extents, a.bytes from user_segments a, user_indexes b where a.segment_name = b.index_name and b.table_name in ('CUST','ADDRESS'); SQL> col segment_name for a30 SQL> col segment_type for a30 SQL> col extents for 999999999999 SQL> col bytes for 999999999999 SQL> SQL> select a.segment_name, a.segment_type, a.extents, a.bytes 2 from user_segments a, user_indexes b 3 where a.segment_name = b.index_name 4 and b.table_name in ('CUST','ADDRESS'); SEGMENT_NAME SEGMENT_TYPE EXTENTS BYTES ------------------------------ ------------------------------ ------------- ------------- CUST_IDX1 INDEX 1 131072 CUST_PK INDEX 1 131072 CUST_UK1 INDEX 1 131072
當向表中插入行時,Oracle將分配由無路數據庫塊組成的區,Oracle還將爲索引分配塊,對於每一個插入到表中的記錄,Oracle還將建立一個包含Rowid和列值的索引條目。
每一個索引項的rowid指向存儲該表的列值的數據文件和塊。ide
當從一個表及其對應的索引選擇數據時,有三種狀況性能
有兩種狀況,在每種狀況下,執行查詢須要的全部數據,包括返回給用戶的數據,以及在where字句中被評估的數據,都位於該索引。 - 索引範圍掃描(index range scan) :若是優化器肯定它使用索引結構檢索查詢所需的多個行是有效的,那麼就使用這種索引。 索引範圍掃描被普遍應用在各類各樣的狀況 - 索引快速全掃描(index fast full scan)若是優化器肯定表中大部分行所須要進行檢索,那麼就使用這種掃描。可是全部須要的信息都存儲在索引中。因爲索引結構一般比表結構小,優化器肯定全索引掃描(比全表掃描)更高效。這種狀況對於統計(count)值的查詢比較常見
以下代碼估算了CUST表的First_name列上建立索引的大小優化
set serverout on exec dbms_stats.gather_table_stats(user,'CUST'); variable used_bytes number variable alloc_bytes number exec dbms_space.create_index_cost('create index cust_idx2 on cust(first_name)',:used_bytes,:alloc_bytes); print :used_bytes print :alloc_bytes SQL> conn testidx/"admin@123" Connected. SQL> set serverout on exec dbms_stats.gather_table_stats(user,'CUST');SQL> PL/SQL procedure successfully completed. SQL> variable used_bytes number SQL> variable alloc_bytes number SQL> exec dbms_space.create_index_cost('create index cust_idx2 on cust(first_name)',:used_bytes,:alloc_bytes); PL/SQL procedure successfully completed. SQL> print :used_bytes USED_BYTES ---------- 25 SQL> print :alloc_bytes ALLOC_BYTES ----------- 65536 SQL> used_bytes變量給出了索引數據須要多少空間的估算 alloc_bytes變量提供了將在表空間分配多大空間的估算。 建立索引 create index cust_idx2 on cust(first_name); select bytes from user_segments where segment_name='CUST_IDX2'; 注意:隨着數據的增長,索引將增大。必須對索引佔用的空間進行監控,確保有足夠的空間,來適應將來的增加需求。
* 如下語句現實了從新建立索引須要的全部方面的語句,這些代碼中的許多值反映了表空間繼承的默認設置和存儲參數。 SQL> set long 10000000 SQL> select dbms_metadata.get_ddl('INDEX','CUST_IDX1') from dual; DBMS_METADATA.GET_DDL('INDEX','CUST_IDX1') -------------------------------------------------------------------------------- CREATE INDEX "TESTIDX"."CUST_IDX1" ON "TESTIDX"."CUST" ("LAST_NAME") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS N OLOGGING STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147483 645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_C ACHE DEFAULT) TABLESPACE "REPORTING_INDEX" * 顯示當前鏈接用戶全部索引的元數據,可運行如下代碼 set long 10000000 select dbms_metadata.get_ddl('INDEX',index_name) from user_indexes; SQL> set long 10000000 SQL> select dbms_metadata.get_ddl('INDEX',index_name) from user_indexes; DBMS_METADATA.GET_DDL('INDEX',INDEX_NAME) -------------------------------------------------------------------------------- CREATE INDEX "TESTIDX"."ADDR_FK1" ON "TESTIDX"."ADDRESS" ("CUST_ID") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS N OLOGGING STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147483 645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_C ACHE DEFAULT) TABLESPACE "REPORTING_INDEX" DBMS_METADATA.GET_DDL('INDEX',INDEX_NAME) -------------------------------------------------------------------------------- CREATE INDEX "TESTIDX"."CUST_IDX1" ON "TESTIDX"."CUST" ("LAST_NAME") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS N OLOGGING STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147483 645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_C ACHE DEFAULT) TABLESPACE "REPORTING_INDEX" DBMS_METADATA.GET_DDL('INDEX',INDEX_NAME) -------------------------------------------------------------------------------- CREATE UNIQUE INDEX "TESTIDX"."CUST_PK" ON "TESTIDX"."CUST" ("CUST_ID") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTIC S NOLOGGING STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147 483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "REPORTING_INDEX" DBMS_METADATA.GET_DDL('INDEX',INDEX_NAME) -------------------------------------------------------------------------------- CREATE UNIQUE INDEX "TESTIDX"."CUST_UK1" ON "TESTIDX"."CUST" ("LAST_NAME", "FIRST_NAME") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS NOLOGGI NG STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE D EFAULT) TABLESPACE "REPORTING_INDEX" SQL>
set linesize 300 col CHECKER for a20 col INDEX_TYPE for a20 col OWNER for a20 col TABLE_NAME for a20 col INDEX_NAME for a20 col CONSTRAINT_NAME for a20 col COLS for a20 SELECT CASE WHEN ind.index_name IS NOT NULL THEN CASE WHEN ind.index_type IN ('BITMAP') THEN '** Bitmp idx **' ELSE 'indexed' END ELSE '** Check idx **' END checker ,ind.index_type ,cons.owner, cons.table_name, ind.index_name, cons.constraint_name, cons.cols FROM (SELECT c.owner, c.table_name, c.constraint_name ,LISTAGG(cc.column_name, ',' ) WITHIN GROUP (ORDER BY cc.column_name) cols FROM dba_constraints c ,dba_cons_columns cc WHERE c.owner = cc.owner AND c.owner = UPPER('&&schema') AND c.constraint_name = cc.constraint_name AND c.constraint_type = 'R' GROUP BY c.owner, c.table_name, c.constraint_name) cons LEFT OUTER JOIN (SELECT table_owner, table_name, index_name, index_type, cbr ,LISTAGG(column_name, ',' ) WITHIN GROUP (ORDER BY column_name) cols FROM (SELECT ic.table_owner, ic.table_name, ic.index_name ,ic.column_name, ic.column_position, i.index_type ,CONNECT_BY_ROOT(ic.column_name) cbr FROM dba_ind_columns ic ,dba_indexes i WHERE ic.table_owner = UPPER('&&schema') AND ic.table_owner = i.table_owner AND ic.table_name = i.table_name AND ic.index_name = i.index_name CONNECT BY PRIOR ic.column_position-1 = ic.column_position AND PRIOR ic.index_name = ic.index_name) GROUP BY table_owner, table_name, index_name, index_type, cbr) ind ON cons.cols = ind.cols AND cons.table_name = ind.table_name AND cons.owner = ind.table_owner ORDER BY checker, cons.owner, cons.table_name; set linesize 300 col CHECKER for a20 col INDEX_TYPE for a20 col OWNER for a20 col TABLE_NAME for a20 col INDEX_NAME for a20 col CONSTRAINT_NAME for a20 col COLS for a20 SQL> SELECT 2 CASE WHEN ind.index_name IS NOT NULL THEN 3 CASE WHEN ind.index_type IN ('BITMAP') THEN 4 '** Bitmp idx **' 5 ELSE 6 'indexed' 7 END 8 ELSE 9 '** Check idx **' 10 END checker 11 ,ind.index_type 12 ,cons.owner, cons.table_name, ind.index_name, cons.constraint_name, cons.cols 13 FROM (SELECT 14 c.owner, c.table_name, c.constraint_name 15 ,LISTAGG(cc.column_name, ',' ) WITHIN GROUP (ORDER BY cc.column_name) cols 16 FROM dba_constraints c 17 ,dba_cons_columns cc 18 WHERE c.owner = cc.owner 19 AND c.owner = UPPER('&&schema') 20 AND c.constraint_name = cc.constraint_name 21 AND c.constraint_type = 'R' 22 GROUP BY c.owner, c.table_name, c.constraint_name) cons 23 LEFT OUTER JOIN 24 (SELECT 25 table_owner, table_name, index_name, index_type, cbr 26 ,LISTAGG(column_name, ',' ) WITHIN GROUP (ORDER BY column_name) cols 27 FROM (SELECT 28 ic.table_owner, ic.table_name, ic.index_name 29 ,ic.column_name, ic.column_position, i.index_type 30 ,CONNECT_BY_ROOT(ic.column_name) cbr 31 FROM dba_ind_columns ic 32 ,dba_indexes i 33 WHERE ic.table_owner = UPPER('&&schema') 34 AND ic.table_owner = i.table_owner 35 AND ic.table_name = i.table_name 36 AND ic.index_name = i.index_name 37 CONNECT BY PRIOR ic.column_position-1 = ic.column_position 38 AND PRIOR ic.index_name = ic.index_name) 39 GROUP BY table_owner, table_name, index_name, index_type, cbr) ind 40 ON cons.cols = ind.cols 41 AND cons.table_name = ind.table_name 42 AND cons.owner = ind.table_owner 43 ORDER BY checker, cons.owner, cons.table_name; Enter value for schema: testidx old 19: AND c.owner = UPPER('&&schema') new 19: AND c.owner = UPPER('testidx') old 33: WHERE ic.table_owner = UPPER('&&schema') new 33: WHERE ic.table_owner = UPPER('testidx') CHECKER INDEX_TYPE OWNER TABLE_NAME INDEX_NAME CONSTRAINT_NAME COLS -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- indexed NORMAL TESTIDX ADDRESS ADDR_FK1 ADDR_FK1 CUST_ID