一、索引概念

索引是一种供服务器在表中快速查找一个行的数据库结构。合理使用索引能够大大提高数据库的运行效率。

在数据库中建立索引主要有以下作用。(1)快速存取数据。  (2)既可以改善数据库性能,又可以保证列值的唯一性。  (3)实现表与表之间的参照完整性  (4)在使用order by、group by子句进行数据检索时,利用索引可以减少排序和分组的时间。

在关系数据库中,每一行都由一个行唯一标识RowID。RowID包括该行所在的文件、在文件中的块数和块中的行号。索引中包含一个索引条目,每一个索引条目都有一个键值和一个RowID,其中键值可以是一列或者多列的组合。

Oracle中提供如下类型的索引B-tree indexes

These indexes are the standard index type. They are excellent for primary key and highly-selective indexes. Used as concatenated indexes, B-tree indexes can retrieve data sorted by the indexed columns. B-tree indexes have the following subtypes:Index-organized tables

An index-organized table differs from a heap-organized because the data is itself the index. See "Overview of Index-Organized Tables".

Reverse key indexes

In this type of index, the bytes of the index key are reversed, for example, 103 is stored as 301. The reversal of bytes spreads out inserts into the index over many blocks. See "Reverse Key Indexes".

Descending indexes

This type of index stores data on a particular column or columns in descending order. See "Ascending and Descending Indexes".

B-tree cluster indexes

This type of index is used to index a table cluster key. Instead of pointing to a row, the key points to the block that contains rows related to the cluster key. See "Overview of Indexed Clusters".

Bitmap and bitmap join indexes

In a bitmap index, an index entry uses a bitmap to point to multiple rows. In contrast, a B-tree index entry points to a single row. A bitmap join index is a bitmap index for the join of two or more tables. See "Bitmap Indexes".

Function-based indexes

This type of index includes columns that are either transformed by a function, such as the UPPER function, or included in an expression. B-tree or bitmap indexes can be function-based. See"Function-Based Indexes".

Application domain indexes

This type of index is created by a user for data in an application-specific domain. The physical index need not use a traditional index structure and can be stored either in the Oracle database as tables or externally as a file. See "Application Domain Indexes".

Hash cluster indexes: defined specifically for a hash cluster

Global and local indexes: relate to partitioned tables and indexes

另外,按照索引所包含的列数可以把索引分为单列索引和复合索引。索引列只有一列的索引为单列索引,对多列同时索引称为复合索引。

B-tree索引结构如下图

当索引列是主键或者该列的选择性很高(数据很少重复)时,适合使用B-Tree索引。

索引中不存储null值,并且索引默认按升序排列。

索引组织表

表中数据按索引的形式组织,表即索引

如图

二、创建索引

创建索引组织表CREATE TABLE indexTable

(

ID     VARCHAR2 (10),

NAME   VARCHAR2 (20),

CONSTRAINT pk_id PRIMARY KEY (ID)

)

ORGANIZATION INDEX;

创建IOT时,必须要设定主键,否则报错

OVERFLOW子句(行溢出)

因为所有数据都放入索引,所以当表的数据量很大时,会降低索引组织表的查询性能。此时设置溢出段将主键和溢出数据分开来存储以提高效率。溢出段的设置有两种格式:

PCTTHRESHOLD n:制定一个数据块的百分比,当行数据占用大小超出时,该行的其他列数据放入溢出段

INCLUDING column_name :指定列之前的列都放入索引块,之后的列都放到溢出段。CREATE TABLE t_iot

(

ID     VARCHAR2 (10),

NAME   VARCHAR2 (20),

CONSTRAINT pk_id PRIMARY KEY (ID)

)

ORGANIZATION INDEX

PCTTHRESHOLD 20

OVERFLOW TABLESPACE users

INCLUDING name;

如上例所示,name及之后的列必然被放入溢出列,而其他列根据 PCTTHRESHOLD 规则。

索引组织表的辅助索引SQL> create index idx_secondary_name on indexTable(name);

Index created.

该索引与堆表的索引有所不同,该索引中的rowid,我们称之为逻辑rowid。是根据索引组织表的主键通过base64算法得出的一个值。

For example, assume that the departments table is index-organized. The location_id column stores the ID of each department. The table stores rows as follows, with the last value as the location ID:10,Administration,200,1700

20,Marketing,201,1800

30,Purchasing,114,1700

40,Human Resources,203,2400

A secondary index on the location_id column might have index entries as follows, where the value following the comma is the logical rowid:1700,*BAFAJqoCwR/+

1700,*BAFAJqoCwQv+

1800,*BAFAJqoCwRX+

2400,*BAFAJqoCwSn+

如果需要为索引组织表创建位图索引的话,需要创建mapping tableSQL> drop index idx_secondary_name;

Index dropped.

SQL> create bitmap index idx_secondary_name on indexTable(name);

create bitmap index idx_secondary_name on indexTable(name)

*

ERROR at line 1:

ORA-28669: bitmap index can not be created on an IOT with no mapping table

mapping table中存储索引组织表的逻辑rowid,bitmap index中存储mapping table数据的rowid。通过访问mapping table将rowid转换成逻辑rowid。

创建mapping tableSQL> alter table indexTable move mapping table;

Table altered.

SQL> create bitmap index idx_secondary_name on indexTable(name);

Index created.

位图索引

当索引列的值重复数据非常多时,适合使用位图索引。位图索引结构如下

与B-tree索引不同,位图索引存储null值,对于count计算有很大的益处。位图索引不适合高并发修改数据,因为修改数据时,需要将索引条目锁定。一个条目(Blue)包含了太多的行。位图索引适合做and or等运算和count统计,比如需要求上例中关键字为Blue的count数,只需计算位图中为1的个数。

对于and 和 or 只需对位图做位运算即可,非常高效。

位图索引还有一个特例,索引列不在主表上,而是由join查询得出。我们看如下图示

在表employees上建立一个位图索引,但是该索引列是由jobs表提供的。

上图示的例子能很好的理解bitmap join 索引,但是不实用。因为在employees的job_id上建立位图索引也能达到相同的效果。

我们假设有Customers,sales两张表,这两张表都很大。

如果有如下需求SELECT SUM (S.AMOUNT_SOLD)

FROM CUSTOMERS C, SALES S

WHERE C.CUST_ID = S.CUST_ID AND C.CUST_CITY = 'Yokohama';

就算cust_id字段上有索引,也不会提高查询性能。

我们可以建立如下索引CREATE BITMAP INDEX cust_sales_bji

ON sales (c.cust_city)

FROM customers c, sales s

WHERE c.cust_id = s.cust_id;SQL> grant select any table to scott;

Grant succeeded.

SQL> conn scott/tiger

Connected.

SQL> create table customers as select * from sh.customers;

Table created.

SQL> ALTER TABLE CUSTOMERS ADD (

CONSTRAINT CUSTOMERS_PK

PRIMARY KEY

(CUST_ID));  2    3    4

Table altered.

SQL>  create table sales as select * from sh.sales;

Table created.

SQL> ALTER TABLE SALES ADD (

CONSTRAINT SALES_PK

PRIMARY KEY

(PROD_ID, CUST_ID, TIME_ID, CHANNEL_ID, PROMO_ID));

Table altered.

SQL> CREATE BITMAP INDEX cust_sales_bji

ON sales (c.cust_city)

FROM customers c, sales s

WHERE c.cust_id = s.cust_id;

Index created.

反转索引

如果某些采用sequence生成值,而该列有建有索引。因为新插入的数据全部都集中在一起,则会引起索引的热点块,降低性能。还会浪费索引的空间,增加索引的高度。因为一旦发生索引块的分裂。较小的索引块将再也不会被使用了。

为了解决此类问题,可以将索引列的值进行反转,然后再建立索引。如值为123456789,反转成987654321.SQL> create table tbl_reverse_idx(id number,text varchar2(30));

Table created.

SQL> insert into tbl_reverse_idx select rownum,object_name from dba_objects;

87084 rows created.

SQL> create index idx_reverse_id on tbl_reverse_idx(id) reverse;

Index created.SQL> select * from tbl_reverse_idx where id=999;

Execution Plan

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

Plan hash value: 1916889338

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

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

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

|   0 | SELECT STATEMENT    |      |     5 |   150 |   135(0)| 00:00:02 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TBL_REVERSE_IDX |     5 |   150 |   135(0)| 00:00:02 |

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

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

这样对范围查询来说,使用索引效率就非常低。SQL> select /*+INDEX(T IDX_REVERSE_ID)*/* from tbl_reverse_idx T  where id between 1000 and 1010;

11 rows selected.

降序索引

对于单列索引,使用降序索引没有意义,因为索引可以重两端扫描。对于复合索引,并且查询语句需要对复合索引中的列按不同顺序排列。

例如查询SQL> select last_name,department_id from hr.employees order by last_name ASC, department_id DESC;

要想避免排序,需要建立如下索引CREATE INDEX emp_name_dpt_ix ON hr.employees(last_name ASC, department_id DESC);

基于函数索引SQL> select * from emp where LOWER(ename)='king';

如果上面的查询要使用索引,则必须建立函数索引SQL> create index idx_emp_ename_lower on emp(lower(ename));

Index created.SQL> select * from emp where LOWER(ename)='king';

Execution Plan

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

Plan hash value: 2294275149

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

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

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

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

|   1 |  TABLE ACCESS BY INDEX ROWID| EMP  |1 |    38 |2   (0)| 00:00:01 |

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

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

部分数据索引

考虑有个表中有一字段PROCESSED_FLAG,它有两个取值N或者Y,Y表示该数据已经被处理过。对于业务来说,每次查询只关心PROCESSED_FLAG=N的,并且PROCESSED_FLAG=N的数据只占用表的很小一部分。如果在该字段上建立普通的索引,那么索引中将有大量的Y,并且还不被查询使用。为了提高效率及减少存储。我们可以在建立索引时做如下变更。SQL> create table big_table as  select * from dba_objects;

Table created.

SQL> select distinct TEMPORARY from big_table;

SQL> select TEMPORARY,count(*) from big_table group by TEMPORARY;

T   COUNT(*)

- ----------

Y 228

N      86859

SQL> create index idx_big_table_temporary on big_table(decode(TEMPORARY,'Y','Y',null));

SQL> select * from big_table where decode(TEMPORARY,'Y','Y',null)='Y';

228 rows selected.

Execution Plan

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

Plan hash value: 1057379504

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

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

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

|   0 | SELECT STATEMENT    |      |   228 | 47652 |     2(0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| BIG_TABLE       |   228 | 47652 |     2(0)| 00:00:01 |

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

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

DML操作与创建索引是互斥的,也就是说正在创建索引时,表不能执行DML操作,正在进行DML的时候不能创建索引。

Oracle引入了online关键字,使得创建索引与DML可以同时进行。

会话1,执行更新操作,但是不提交SQL> update big_table set object_name=lower(object_name);

87087 rows updated.

会话2建立索引SQL> create index idx_big_table_oname on big_table(object_name);

create index idx_big_table_oname on big_table(object_name)

*

ERROR at line 1:

ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired

在线建立索引。SQL> create index idx_big_table_oname on big_table(object_name) online;

Index created.

三、索引维护

修改索引的存储属性

ALTER INDEX emp_ename

STORAGE (PCTINCREASE 50);

当索引中有碎片时,可以使用索引重建或者合并来解决。

重建索引ALTER INDEX emp_name REBUILD;ALTER INDEX emp_name REBUILD ONLINE;

索引合并ALTER INDEX vmoore COALESCE;

将索引标记为unusable

当索引为unusable时,优化器将忽略索引,并且DML不再维护索引(如果是唯一索引,dml操作将报错)。当需要大批量数据导入时,可以将索引unusable以提高导入的性能。ALTER INDEX emp_email_uk UNUSABLE;ALTER INDEX i_emp_ename MODIFY PARTITION p2_i_emp_ename UNUSABLE;

unusable的索引要想再次生效,必须使用rebuild index。

将索引标记为Invisible

当索引为Invisible时,优化器将忽略索引,但是DML继续维护索引。分区索引不能单独的将某个分区Invisible。ALTER INDEX index INVISIBLE;ALTER INDEX index VISIBLE;

重命名索引ALTER INDEX index_name RENAME TO new_name;

监控索引是否被使用

系统建立索引后,到底业务查询有没有使用呢?SQL> alter index idx_big_table_oname monitoring usage;

Index altered.

Oracle提供如下视图监控索引的使用情况SQL> select * from  V$OBJECT_USAGE;

INDEX_NAME       TABLE_NAME      MON USE START_MONITORING  END_MONITORING

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

IDX_BIG_TABLE_ONAME       BIG_TABLE      YES NO  09/09/2015 20:10:56

当索引被使用以后SQL> select object_name from big_table where object_name='EMP';

OBJECT_NAME

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

EMP

SQL> select * from  V$OBJECT_USAGE;

INDEX_NAME       TABLE_NAME      MON USE START_MONITORING  END_MONITORING

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

IDX_BIG_TABLE_ONAME       BIG_TABLE      YES YES 09/09/2015 20:10:56

监控索引的使用空间

当表频繁的插入、删除、更新。有可能索引会有碎片。可以通过如下方式来检查索引的空间使用率。

生成一张表CREATE TABLE t1

AS

SELECT ROWNUM rn,

DBMS_RANDOM.string ('u', 20) name1,

DBMS_RANDOM.string ('u', 15) name2

FROM DUAL

CONNECT BY LEVEL

create index i1 on t1(rn);

analyze index i1 validate structure;

SQL> select height,lf_rows,del_lf_rows,lf_blks,del_lf_rows btree_space,used_space,pct_used from index_stats;

HEIGHT    LF_ROWS DEL_LF_ROWS    LF_BLKS BTREE_SPACE USED_SPACE   PCT_USED

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

3     99999902226       0   16006445    90

SQL> delete from t1 where mod(rn,2) =1;

500000 rows deleted.

SQL> analyze index i1 validate structure;

Index analyzed.

SQL> select height,lf_rows,del_lf_rows,lf_blks,del_lf_rows btree_space,used_space,pct_used from index_stats;

HEIGHT    LF_ROWS DEL_LF_ROWS    LF_BLKS BTREE_SPACE USED_SPACE   PCT_USED

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

3     695404   1954052226  195405   11132925    63

SQL>  alter index i1 rebuild online;

Index altered.

SQL>  analyze index i1 validate structure;

Index analyzed.

SQL> select height,lf_rows,del_lf_rows,lf_blks,del_lf_rows btree_space,used_space,pct_used from index_stats;

HEIGHT    LF_ROWS DEL_LF_ROWS    LF_BLKS BTREE_SPACE USED_SPACE   PCT_USED

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

3     49999901113       0    7998149    90

索引的集群因子

什么是集群因子(Clustering Factor)呢?集群因子是通过一个索引扫描一张表时需要访问的表的数据块的数量。集群因子的计算方法如下:

(1) 扫描一个索引;

(2) 比较某行的ROWID和前一行的ROWID,如果这两个ROWID不属于同一个数据块,那么集群因子增加1;

(3) 整个索引扫描完毕后,就得到了该索引的集群因子。

以上面集群因子的计算方式可以看出,集群因子反映了索引范围扫描可能带来的对整个表访问过程的IO开销情况,如果集群因子接近于表存储的块数,说明这张表是按照索引字段的顺序存储的。如果集群因子接近于行的数量,那说明这张表不是按索引字段顺序存储的。在计算索引访问成本时,集群因子十分有用。集群因子乘以选择性参数就是访问索引的开销。

如果这个统计数据不能反映出索引的真实情况,那么可能会造成优化器错误地选择执行计划。另外,如果某张表上的大多数访问是按照某个索引做索引扫描,那么将该表的数据按照索引字段的顺序重新组织,可以提高该表的访问性能。

我们看两个图就明白了集群因子

可见集群因子越高,范围扫描的性能越低。

查看索引的集群因子SQL> SELECT INDEX_NAME, CLUSTERING_FACTOR

FROM ALL_INDEXES

WHERE INDEX_NAME IN ('PK_EMP','IDX_EMP_ENAME_LOWER');  2    3

INDEX_NAME       CLUSTERING_FACTOR

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

IDX_EMP_ENAME_LOWER      28

PK_EMP       2

重建索引并不能减少集群因子

oracle优化器analyzed,Oracle 学习之 性能优化(十三) 索引相关推荐

  1. 如何学习Linux性能优化?

    如何学习Linux性能优化? 你是否也曾跟我一样,看了很多书.学了很多 Linux 性能工具,但在面对 Linux 性能问题时,还是束手无策?实际上,性能分析和优化始终是大多数软件工程师的一个痛点.但 ...

  2. 6个最好的WordPress图像优化器插件提高WordPress网站性能

    WordPress图像优化器插件, wordpress建站, wordpress教程 提升WordPress网站的性能发生在几个层面,可以做一些事情来优化网站,有很多非常好的图像压缩和优化工具.选择正 ...

  3. 前端性能优化(二)01-页面性能优化之浏览器——浏览器的主要作用 浏览器的组成结构

    前端性能优化(二)01-页面性能优化之浏览器--浏览器的主要作用 & 浏览器的组成结构 页面性能优化 前端性能优化可以分为两大部分:浏览器部分.代码部分. 浏览器部分又可以分为: 网络层面 浏 ...

  4. 动态优化器—一种感知视频编码优化框架

    Netflix提出了一种基于感知视频编码优化框架,在非峰值流时间期间,将此编码系统应用于AVC-High和VP9数据流,提高了用户的视频质量的同时并节省了带宽.LiveVideoStack对本文进行了 ...

  5. 性能优化系列(五)网络性能优化

    文章首发「Android波斯湾」公众号,更新地址:https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode 移动互联网时代,用户对网 ...

  6. 搜索引擎优化(SEO)之 前端性能优化技巧

    什么是SEO 先让我们了解搜索引擎SEO,这个视频 How Search Works 解释了搜索引擎是如何工作的. 在让我们摘一下百度百科 SEO(Search Engine Optimization ...

  7. linux性能优化实战 倪朋飞,Linux性能优化实战:系统的swap变高(09)

    一.实验环境 1.操作系统 root@openstack:~# lsb_release -a No LSB modules are available. Distributor ID:Ubuntu D ...

  8. 前端性能优化:1.什么是前端性能优化

    1.1 性能的起因 人无我有,人有我优,人优我廉,人廉我专 1.2 性能的影响 1.2.1 用户的留存 根据Google营销平台提供的调研发现,如果网站页面加载时间超过3,就会有53%的移动网站的访问 ...

  9. C++性能优化(一)——应用程序性能优化简介

    一.程序性能优化简介 1.程序性能优化简介 在计算机发展的早期阶段,硬件资源相对而言是非常昂贵的,CPU运行时间与内存容量给程序开发人员设置了极大限制.因此,早期的程序对运行性能和内存空间占用的要求是 ...

  10. oracle并行收集统计信息慢,Oracle 学习之性能优化(四)收集统计信息

    emp表有如下数据.SQL> select ename,deptno from emp; ENAME   DEPTNO ------------------------------ ------ ...

最新文章

  1. 高校毕业生:今年“太惨了”,网友:更惨的可能还在后头!
  2. 独木舟上的旅行http://acm.nyist.net/JudgeOnline/problem.php?pid=71
  3. 关于VC中的stdafx.h
  4. python【数据结构与算法】计数问题(分治)
  5. Kafka如何通过精妙的架构设计优化JVM GC问题
  6. 以前我们学计算机编程,在编程之前像计算机一样思考
  7. junit 测试 dao_JUnit测试Spring Service和DAO(带有内存数据库)
  8. 在ArcEngine中使用Geoprocessing工具-执行工具
  9. AS函数的一些特殊应用
  10. 证券市场的法律法规体系
  11. 用Hadoop构建电影推荐系统
  12. 正则表达式 不含指定字符串
  13. python读取整个txt文件-python读取一个目录下所有txt里面的内容方法
  14. GLSL——绘制平面图形(二)
  15. Linux驱动之 原子操作
  16. 苹果手机打字换行怎么换_苹果id怎么换
  17. torch学习 (三十二):周杰伦歌词数据集与长短期记忆 (LSTM)
  18. 前端每日实战:97# 视频演示如何用纯 CSS 创作一组昂首阔步的圆点
  19. 超级计算机比赛规则,“ISC12国际大学生超级计算机竞赛”比赛规则介绍
  20. TensorFlow Object Detection API 超详细教程和踩坑过程

热门文章

  1. 机器学习方向上还有没有创新点呢?
  2. MSN的聊天记录在哪里找到?
  3. 输入年份和月份输出该月有多少天python_题目内容:读入一个年份和月份,输出该月有多少天(考虑闰年),用s? 爱问知识人...
  4. 部署nodejs报No package nodejs available
  5. Word控件Spire.Doc 转换教程(二十一):将非标准字体的word文档转换为PDF
  6. css 超链接的颜色,css超链接字体颜色
  7. python3调用谷歌翻译_使用python3调用谷歌翻译成中文
  8. Arcscene教程
  9. 融资融券的交易成本有哪些?
  10. 三年硬件工程师薪水_硬件研发工程师,工资不高的真相