oracle 索引优化

标签: oracle 索引 优化 | 发表时间:2014-11-16 21:33 | 作者:xuyunti
出处:http://www.iteye.com

 原文 http://blog.sina.com.cn/s/blog_6ceed3280101206m.html

 

表:gzl_action_define

字段:id:主键,有索引
name:一般字段,无索引
以下是各种写法的结果

1.使用索引(UNIQUE SCAN)

select t.name from gzl_action_define t where t.id = '12'

2.使用索引(RANGE SCAN)

select t.name from gzl_action_define t where t.id like '12%'

3.不使用索引(TABLE ACCESS (FULL))

select t.name from gzl_action_define t where t.id like ''

4.使用索引(FAST FULL SCAN)

select t.id from gzl_action_define t where t.id like ''

5.不使用索引(TABLE ACCESS (FULL))

select t.name from gzl_action_define t where t.id like '%'

6.使用索引(FAST FULL SCAN)

select t.id from gzl_action_define t where t.id like '%'

------------------------------------------------------------------------------------------
 
 Oracle 索引相关理论知识
*声明:以下内容,来源于网络资源*

 

*(一)  * *建立索引常用的规则如下:*

1)         表的主键、外键必须有索引;

2)         数据量超过300的表应该有索引;

3)         经常与其他表进行连接的表,在连接字段上应该建立索引;

4)         经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;

5)         索引应该建在选择性高的字段上;

6)         索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;

7)         复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:

a)         正确选择复合索引中的主列字段,一般是选择性较好的字段;

b)         复合索引的几个字段是否经常同时以AND方式出现在Where
子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引;

c)         如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;

d)         如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段;

e)         如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;

8)         频繁进行数据操作的表,不要建立太多的索引;

*9)        * *删除无用的索引,避免对执行计划造成负面影响;*

以上是一些普遍的建立索引时的判断依据。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。因为太多的索引与不充分、不正确的索引对性能都毫无益处:在表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。
另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大。

*(二)  * *避免对列的操作:*

1)         任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等等,查询时要*
尽可能将操作移至等式的右边,甚至去掉函数。*

例1:下列SQL条件语句中的列都建有恰当的索引,但30万行数据情况下执行速度却非常慢:

select * from record where  substrb(CardNo,1,4)='5378'(13秒)

select * from record where  amount/30< 1000(11秒)

select * from record where  to_char(ActionTime,'yyyymmdd')='19991201'(10秒)

由于where子句中对列的任何操作结果都是在SQL
运行时逐行计算得到的,因此它不得不进行表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL
优化器优化,使用索引,避免表扫描,因此将SQL重写如下:

select * from record where CardNo like  '5378%'(< 1秒)

select * from record where amount  < 1000*30(< 1秒)

select * from record where ActionTime= to_date ('19991201' ,'yyyymmdd')(< 1秒)

(三)   *避免不必要的类型转换:*

1)         尽量避免潜在的数据类型转换。如将字符型数据与数值型数据比较,ORACLE会自动将字符型用to_number()
函数进行转换,从而导致全表扫描。

例2:表tab1中的列col1是字符型(char),则以下语句存在类型转换:

select col1,col2 from tab1 where col1>10;

应该写为: select col1,col2 from tab1 where col1>'10'

*(四)  * *增加查询的范围限制*

1)         增加查询的范围限制,避免全范围的搜索

例3:以下查询表record 中时间ActionTime小于2001年3月1日的数据

select * from record where ActionTime < to_date ('20010301' ,'yyyymm')

查询计划表明,上面的查询对表进行全表扫描,如果我们知道表中的最早的数据为2001年1月1日,那么,可以增加一个最小时间,使查询在一个完整的范围之内:

select * from record where ActionTime < to_date ('20010301' ,'yyyymm') and  
 ActionTime > to_date ('20010101' ,'yyyymm')

后一种SQL语句将利用上ActionTime字段上的索引,从而提高查询效率。把'20010301'
换成一个变量,根据取值的机率,可以有一半以上的机会提高效率。同理,对于大于某个值的查询,如果知道当前可能的最大值,也可以在Where子句中加上 “AND
列名< MAX(最大值)”。

*(五)  * *尽量去掉"IN"**、"OR"*

*1)        * 含有"IN"、"OR"的Where
子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。

例4:select count(*) from stuff where id_no in('0','1')(23秒)

可以考虑将or子句分开:

select count(*) from stuff where id_no='0'  

select count(*) from stuff where id_no='1'

然后再做一个简单的加法,与原来的SQL语句相比,查询速度更快

*(六)  * *尽量去掉 "<>"*

*1)        * 尽量去掉 "<>",避免全表扫描,如果数据是枚举值,且取值范围固定,则修改为"OR"方式

例5:UPDATE SERVICEINFO SET STATE=0 WHERE STATE<>0;

以上语句由于其中包含了"<>",执行计划中用了全表扫描(TABLE ACCESS FULL),没有用到state
字段上的索引。实际应用中,由于业务逻辑的限制,字段state为枚举值,只能等于0,1或2,而且,值等于=1,2的很少,因此可以去掉"<>"
,利用索引来提高效率。

修改为:UPDATE SERVICEINFO SET STATE=0  WHERE STATE = 1 OR STATE = 2
。进一步的修改可以参考第4种方法

*(七)  * *去掉Where**子句中的IS NULL**和IS NOT NULL*

*1)        * Where字句中的IS NULL和IS NOT NULL
将不会使用索引而是进行全表搜索,因此需要通过改变查询方式,分情况讨论等方法,去掉Where子句中的IS NULL和IS NOT NULL。

*(八)  * *索引提高数据分布不均匀时查询效率*

1)         索引的选择性低,但数据的值分布差异很大时,仍然可以利用索引提高效率。

A、数据分布不均匀的特殊情况下,选择性不高的索引也要创建。

表ServiceInfo中数据量很大,假设有一百万行,其中有一个字段DisposalCourseFlag,取值范围为枚举值:[0,1,2,3,4,5,6
,7]。按照前面说的索引建立的规则,“选择性不高的字段不应该建立索引,该字段只有8
种取值,索引值的重复率很高,索引选择性明显很低,因此不建索引。然而,由于该字段上数据值的分布情况非常特殊,具体如下表:

取值范围                   1~5        6        7
占总数据量的百分比        1%        98%        1%

而且,常用的查询中,查询DisposalCourseFlag<6
的情况既多又频繁,毫无疑问,如果能够建立索引,并且被应用,那么将大大提高这种情况的查询效率。因此,我们需要在该字段上建立索引。

*(九)  * *like**子句尽量前端匹配*

*1)        * 因为like参数使用的非常频繁,因此如果能够对like子句使用索引,将很高的提高查询的效率。

例6:select * from city where name like ‘%S%’

以上查询的执行计划用了全表扫描(TABLE ACCESS FULL),如果能够修改为:

select * from city where name like ‘S%’

那么查询的执行计划将会变成(INDEX RANGE SCAN),成功的利用了name字段的索引。这意味着Oracle SQL优化器会识别出用于索引的
like子句,只要该查询的匹配端是具体值。因此我们在做like查询时,应该尽量使查询的匹配端是具体值,即使用like ‘S%’。

*(十)  * *用Case**语句合并多重扫描*

1)         我们常常必须基于多组数据表计算不同的聚集。例如下例通过三个独立查询:

例8:1)select count(*) from emp where sal<1000;

2)select count(*) from emp where sal between 1000 and 5000;

3)select count(*) from emp where sal>5000;

这样我们需要进行三次全表查询,但是如果我们使用case语句:

select
count (sale when sal <1000
then 1 else null end)                count_poor,
count (sale when between 1000 and 5000
then 1 else null end)                count_blue_collar,
count (sale when sal >5000
then 1 else null end)                count_poor
from emp;
这样查询的结果一样,但是执行计划只进行了一次全表查询。

*(十一)        * *使用基于函数的索引*

1)         select * from emp where substr(ename,1,2)=’SM’;

可以创建一个带有substr函数的基于函数的索引:

create index emp_ename_substr on eemp ( substr(ename,1,2) );

这样在执行上面的查询语句时,这个基于函数的索引将排上用场,执行计划将是(INDEX RANGE SCAN)。

*(十二)        * *基于函数的索引要求等式匹配*

1)         创建了基于函数的索引,但是如果执行下面的查询:

select * from emp where substr(ename,1,1)=’S’

得到的执行计划将还是(TABLE ACCESS FULL
),因为只有当数据列能够等式匹配时,基于函数的索引才能生效,这样对于这种索引的计划和维护的要求都很高。请注意,向表中添加索引是非常危险的操作,因为这将导致许多查询执行计划的变更。然而,如果我们使用基于函数的索引就不会产生这样的问题,因为
Oracle只有在查询使用了匹配的内置函数时才会使用这种类型的索引。

*(十三)        * *决定使用全表扫描还是使用索引*

1)         
在大多数情况下,全表扫描可能会导致更多的物理磁盘输入输出,但是全表扫描有时又可能会因为高度并行化的存在而执行的更快。如果查询的表完全没有顺序,那么一个要返回记录数小于
10%的查询可能会读取表中大部分的数据块,这样使用索引会使查询效率提高很多。但是如果表非常有顺序,那么如果查询的记录数大于40
%时,可能使用全表扫描更快。因此,有一个索引范围扫描的总体原则是:

a)         对于原始排序的表  仅读取少于表记录数40%的查询应该使用索引范围扫描。反之,读取记录数目多于表记录数的40
%的查询应该使用全表扫描。

*b)       * 对于未排序的表    仅读取少于表记录数7%的查询应该使用索引范围扫描。反之,读取记录数目多于表记录数的7
%的查询应该使用全表扫描。

 

随着时间的推移和数据的累计与变化,ORACLE对SQL
语句的执行计划也会改变,比如:基于代价的优化方法,随着数据量的增大,优化器可能错误的不选择索引而采用全表扫描。这种情况可能是因为统计信息已经过时,在数据量变化很大后没有及时分析表;但如果对表进行分析之后,仍然没有用上合理的索引,那么就有必要对
SQL语句用HINT提示,强制用合理的索引。但这种HINT
提示也不能滥用,因为这种方法过于复杂,缺乏通用性和应变能力,同时也增加了维护上的代价;相对来说,基于函数右移、去掉“IN ,OR ,<> ,IS
NOT NULL ”、分解复杂的SQL语句等等方法,却是“放之四海皆准”的,可以放心大胆的使用。



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [oracle 索引 优化] 推荐:

oracle 索引优化

- - Oracle - 数据库 - ITeye博客
表:gzl_action_define. 字段:id:主键,有索引. name:一般字段,无索引. 1.使用索引(UNIQUE SCAN). 2.使用索引(RANGE SCAN). 3.不使用索引(TABLE ACCESS (FULL)). 4.使用索引(FAST FULL SCAN). 5.不使用索引(TABLE ACCESS (FULL)).

oracle 索引

- - 数据库 - ITeye博客
        自动:在使用primary和unique后系统会自动创建唯一索引.         手动:create   index   索引名  on 表名(字段1,....). 查询表上有哪些索引(网上找的,能用,表名和索引名要大写). 1、查找表的所有索引(包括索引名,类型,构成列):. select t.*,i.index_type from user_ind_columns t,user_indexes i where t.index_name = i.index_name and t.table_name = i.table_name and t.table_name = 要查询的表.

Oracle索引

- - Oracle - 数据库 - ITeye博客
在关系数据库中,索引是一种与表有关的数据库结构,它可以使对应于表的SQL语句执行得更快. 索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容. 对于数据库来说,索引是一个必选项,但对于现在的各种大型数据库来说,索引可以大大提高数据库的性能,以至于它变成了数据库不可缺少的一部分. singlecolumnorconcatenated  对一列或多列建所引.

Oracle索引管理

- - CSDN博客数据库推荐文章
     语法:create index 索引名称 on 表名称(列名称1,列名称2,.......) tablespace 表空间名称;.     例子:create index  ind_enno on test01(enno) tablespace system;.     创建唯一索引:create unique index 索引名称 on 表名称(列名称1,列名称2,......) tablespace 表空间名称.

Oracle 索引详解

- - Oracle - 数据库 - ITeye博客
 1.1 索引的创建语法: . 1) UNIQUE | BITMAP:指定UNIQUE为唯一值索引,BITMAP为位图索引,省略为B-Tree索引. 2) |  ASC | DESC:可以对多列进行联合索引,当为expression时即“基于函数的索引”.

oracle B*树索引

- - 数据库 - ITeye博客
        B*树索引是最常用的数据库索引,一般所说的索引都是B*树索引.         B*树索引的构造类似于二叉树,能根据键提供一行或一个行集的快速访问,通常只需要很少的读操作就能找到正确的行.         B*树索引的结构有可能如下图所示.         这个树最底层的块称为叶子节点(leaf node)或叶子块(leaf block),其中分别包含各个索引建以及一个rowid(指向所索引的行).

oracle性能优化

- - 行业应用 - ITeye博客
                              oracle数据库的性能优化. 主要从内部存储结构,逻辑分区,表结构范式,sql语句优化. hibernate处的层次更高,主要从缓存,和sql语句的使用.     对于ORACLE数据库的数据存取,主要有四个不同的调整级别,第一级调整是操作系统级包括硬件平台,第二级调整是ORACLE RDBMS级的调整,第三级是数据库设计级的调整,最后一个调整级是SQL级.

Oracle的索引结构

- - 数据库 - ITeye博客
 B*树索引就是我们说的“传统”索引,这是数据库中最常用的一类索引结构. 其实现与二叉查找树类似,目标是减少oracle查找数据的时间. 如果在一个数字列上有一个索引,那么理论上结构应该是这样的:.         这个树最底层是叶子节点,包含索引键以及一个rowid(指向索引行). 叶子节点上面的称为分支块,用于在结构中实现导航.

oracle sql 优化大全

- - Oracle - 数据库 - ITeye博客
最近遇到了oracle sql优化的问题,找了一下,发现这文章实在不错,跟大家分享一下,如果以后有什么新的改进也会继续补充的. 1     前言… 2 . 2     总纲… 2 . 3     降龙十八掌… 3 . 第一掌 避免对列的操作… 3 . 第二掌 避免不必要的类型转换… 4 . 第三掌 增加查询的范围限制… 4 .

Oracle SQL性能优化

- - 数据库 - ITeye博客
(1)      选择最有效率的表名顺序(只在基于规则的优化器中有效):. ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表. 如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.