首页 > 代码库 > Oracle大数据查询优化

Oracle大数据查询优化

1、对于像状态之类的列,不是很多的,就可以加位图索引,对于唯一的列,就加唯一索引,其余的创建普通索引。

2、尽量不要使用select * 这样的查询,指定需要查询的列。

3、使用hits  select /*+index(索引名称) index(索引名称)*/ supply_id from CSS_SUPPLY  where ...

4、将表table在线重定义为分区表,在name列上使用hash分区或者range分区

5、如果是exedata平台,不要用索引,尽量少用hint;

6、用并行;

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

    |   Oracle的索引      |

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

    Oracle提供大量的索引选项,使用索引的目的是为了加快查询速度、减少I/O操作和消除磁盘排序,那么在何种情况下建立索引才能发挥索引的作用呢?通常情况下建立索引的规则[2]可描述如下: (1) 表的主键和外键必须有索引; (2) 对经常与其他表进行连接的表的连接字段应该建立索引; (3) 经常出现在Where子句中的字段应该建立索引(尤其是数据量较大的表的字段); (4) 选择性高的字段应该建立索引; 索引的选择性是指索引列里不同值的数目与表中记录数的比。如果表中有1000个记录,表索引列有950个不同的值,那么这个索引的选择性就是0.95。最好的可能性选择是1.0,依据非空值列的唯一索引,通常其选择性为1.0。 (5) 小字段应该建立索引,对于较长的文本字段甚至超长字段,不要建索引; (6) 复合索引的建立需要经过仔细分析,尽量考虑用单字段索引代替;      ① 正确选择复合索引中主列字段,一般是选择“选择性”较好 的字段;     ② 复合索引的几个字段是否经常同时以AND方式出现在Where子句中?单字段的查询是否极少甚至没有?如果以上两种情况或两者之一,则应该建立复合索引,否则考虑单字段索引;     ③ 如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;     ④ 复合索引所包含的字段一般不要超过3个,否则需要仔细考虑其必要性;     ⑤ 如果既有单字段索引,又有包含这几个字段的复合索引,一般可以删除复合索引;     ⑥ 建立复合索引的特殊情况:如果表中的数据相当稳定且字段不多,可以考虑充分索引一个表,即创建一个复合索引,它包括所有在查询期间通常会被选择的列,查询所要求的所有数据可以通过索引访问提供,避免了索引扫描随后的任何表访问。

(7) 频繁进行插入、删除操作的表,不要建立过多索引; (8) 删除无用索引,避免对执行计划造成负面影响;

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

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

    |    SQL语句的优化    |

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

    正确地使用索引,可以理使用资源,使得数据的查询速度加快。但是,建立索引之后,并非就意味着查询时的速度得到了提高,这时还需要有良好的SQL语句进行支持,才能使得查询中利用索引从而提高查询的速度。下面将对如何在SQL语句中利用索引来提高查询速度进行一下分析。

(1) IS NULL 与 IS NOT NULL      不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。 

(2) 联接列     对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。比如下面的sql语句 select * from oil where oil_name||‘ ‘||oil_id =‘胜坨 shengtuo‘;

要查询油田为“胜坨 shengtuo”的油田的数据,假设在oil_id列已经建了索引,此sql语句虽然也能实现正确的查询,但系统优化器对基于oil_id创建的索引却没有使用。如果改为以下的sql语句 select * from oil where oil_name =‘胜坨’and oil_id= ‘shengtuo‘;

Oracle系统就可以采用基于oil_id创建的索引。

(3) 带通配符(%)的like语句 

    同样以上面的例子来看这种情况。目前的需求是这样的,要求在oil表中查询名称中包含胜坨的油。可以采用如下的查询SQL语句:select * from employee where oil_name like ‘%胜坨%‘;     在以上sql语句中通配符(%)在搜寻词首出现,所以Oracle系统不使用oil_id的索引。不过在很多情况下可能无法避免这种情况,但是需要了解的是如此使用通配符会降低查询速度。不过当通配符出现在字符串的其它位置时,优化器就可以利用索引了,例如以下的查询就可以利用索引: select * from employee where oil_name like ‘胜坨%‘;

(4) Order by语句     order by语句决定了Oracle如何将返回的查询结果排序。order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(像联接或者附加等)。任何在order by语句的非索引项或者有计算表达式都将降低查询速度。 仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。

(5) NOT     在查询中,我们经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也会用到and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反,比如... where not (oil_id=‘shengtuo‘)  如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上not运算符。not运算符包含在另外一个逻辑运算符中,这就是不等于(<>)运算符。也可以说,即使不在查询where子句中显式地加入not词,not仍在运算符中。 

看下面两条sql语句: 

select * from oil where productoil <>3000;  select * from oil where productoil <3000 or productoil >3000;

    虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对productoil列使用索引,而第一种查询则不能使用索引。 

(6) IN和EXISTS 

    在查询中,我们也经常会用到两列进行比较的情况,最简单的方法是在where句子中使用子查询,而这种子查询一般有两种形式。 一种是利用in操作符:... where column in (select * from ...where ...); 另一种是使用exist操作符:... where exists (select ‘X‘ from ...where ...);

    对于这两种格式的子查询语句,一般都会使用第一种是用in操作符的查询,因为这种语句比较容易些,也很直观,但实际上却是第二种格式的子查询效率会更高。在Oracle中可以将几乎所有的in操作符子查询改写为使用exists的子查询。     第二种格式中,子查询以‘select ‘X‘’开始。运用exists子句不管子查询从表中抽取什么数据它只查看where子句的特点,这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,exists使用相连子查询,构造起来要比in子查询困难一些。     通过使用exists,Oracle系统会首先检查主查询,然后运行子查询直到找到第一个匹配项,这就节省了时间。Oracle系统在执行in子查询时,首先执行子查询,并将获得的结果列表存放在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用exists比使用in通常查询速度快的原因。 

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

    |          临时表        |

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

  目前大部分使用Oracle作为数据库的系统数据量都比较庞大,在使用时我们经常会用到有多个表关联的情况,而且这些表大部分都比较庞大,但是当进行关联的时候却发现某一个表或几个表关联之后得到的结果集很小而且查询这个结果集的速度也非常快,那么这时候我们就可以考虑在Oracle中创建“临时表”。这样在工程中多次用到这些数据时直接查询临时表的速度要快很多,而当用完之后表中的数据就没用了,而且Oracle的临时表创建之后基本不占用表空间。  与使用永久表不同,添加或者更改临时表中的数据并不会生成重做日志条目,但是,它会生成撤销日志条目。永久表与临时表之间的另一项区别是片段的分配。临时表使用临时片段,并且在表中实际插入数据之前,不会向表分配临时片段。

    ORACLE数据库系统的临时表有两种,一种是事务型临时表,一种是会话型临时表。事物型临时表是当一个事务结束时清空临时表的内容;而会话型临时表就当一个会话中断或者被重新连接时数据表的内容就会清空了。ORACLE数据库在清除临时表时,只清除数据,而不清楚临时表的本身。ORACLE还提供了一种更加细分的事务型临时表。一个会话中,可能有多个事务。也就是说,ORACLE清空临时型数据表的时间更加细腻,可以根据同一个会话中的不同事务来清空临时表。另外还要说明的一点就是,ORACLE的会话型临时中的内容对于各个用户来说,内容都是独立的。具体的说,就是各个用户在会话的过程中,都可以往一张临时表中存储数据;但是用户查询临时表中的数据的时候,只能够查询到自己所创建的内容,而不能看到其他用户所增加的记录。这对于临时表的安全性来说,是非常有保障的。     临时表也有局限性,比如:

  (1) 临时表只在当前连接内有效;

  (2) 临时表不建立索引,所以如果数据量比较大或进行多次查询时,不推荐使用;

  (3) 数据处理比较复杂的时候时较快,反之视图快点。

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

    |          总结           |  

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

  综上所述,在进行简单查询时,充分利用索引,并合理的优化SQL语句来有效的利用索引,可以减少响应时间。而在工程中利用临时表减少数据的访问量、提高数据库操作的效率,从而减少响应时间。但是以上的优化方法都是作为参考用的,优化必须随着系统应用情况的变化和数据量的变化而调整,灵活地采取优化手段才能有效地提高系统效率。