介绍B树索引

B树索引

简介

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;

给地址表添加外键约束,外键索引对应cust表的cust_id列

ALTER TABLE address ADD CONSTRAINT addr_fk1 FOREIGN KEY (cust_id) REFERENCES cust(cust_id);

创建address表的外键索引

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指向存储该表的列值的数据文件和块。

当从一个表及其对应的索引选择数据时,有三种情况

  • SQL查询所需要的所有表的数据都在索引中,因此只需要访问索引块,不需要从表中读取块。
  • 查询所需的所有信息没有都包含在索引块中,因此查询优化器选择既访问索引块也访问表块来检索需要的数据,以满足查询的结果。
  • 查询优化器选择不访问索引。因此只访问表块。

场景一:所有数据位于索引块。

有两种情况,在每种情况下,执行查询需要的所有数据,包括返回给用户的数据,以及在where字句中被评估的数据,都位于该索引。
- 索引范围扫描(index range scan) :如果优化器确定它使用索引结构检索查询所需的多个行是有效的,那么就使用这种索引。 索引范围扫描被广泛应用在各种各样的情况
- 索引快速全扫描(index fast full scan)如果优化器确定表中大部分行所需要进行检索,那么就使用这种扫描。但是所有需要的信息都存储在索引中。由于索引结构通常比表结构小,优化器确定全索引扫描(比全表扫描)更高效。这种情况对于统计(count)值的查询比较常见

演示1 索引范围扫描

场景二: 索引中不包含所有信息

场景三: 只有表被访问信息

在创建前估算索引表大小

显示创建索引的代码

删除B树索引

管理带约束的B树索引

输入一个模式,查询是否存在相应的外键约束

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
上一篇:Lifecycle


下一篇:使用ogg实现oracle到postgresql表的实时同步