在多数情况下,Oracle使用索引t来更快地遍历表,优化器主要根据定义的索引来提高性能。

但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种SQL语句就是所谓的劣质SQL语句。

在编写SQL语句时我们应清楚优化器根据何种原则来删除索引,这有助于写出高性能的SQL语句

1. IS NULL 与 IS NOT NULL

不能用null作索引,任何包含null值的列都将不会被包含在索引中。

即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。

也就是说如果某列存在空值,即使对该列建索引也不会提高性能。

任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的

如果我们必须要用 is null,又需要提供查询效率 可以用函数索引

实例如下

create table test_date (name varchar2(),day date);
insert into test_date(name ,day) values ('lucy',null);
insert into test_date(name ,day) values ('jony',null);
insert into test_date(name,day) values ('james',sysdate);
select * from test_date;
--创建decode函数索引来代替
create   index  finx_day on  test_date(decode(day,null,'N', 'Y'))

--使用decode判断来代替is null判断
select * from test_date a where  decode(day,null,'N','Y') = 'N'

2. 联接列

对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。

假定有一个职工表(employee),对于一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),

现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。

下面是一个采用联接查询的SQL语句,

select * from employs where
first_name||’ ’||last_name ='Beill Cliton'

上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。

当采用下面这种SQL语句的编写,Oracle系统就可以采用基于last_name创建的索引。

Select * from employee where
first_name ='Beill' and last_name ='Cliton'

如果一个变量(name)中存放着Bill Cliton这个员工的姓名,对于这种情况我们又如何避免全程遍历?

可以使用一个函数,将变量name中的姓和名分开就可以了,但是有一点需要注意,这个函数是不能作用在索引列上。‘

下面是SQL查询脚本

select * from employee
where
first_name = SUBSTR(,INSTR()
and
last_name = SUBSTR('&&name',INSTR('&&name’,' ')+1)

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

以如下SQL讲解:

select * from employee where last_name like '%cliton%'

这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引。

在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。

然而当通配符出现在字符串其他位置时,优化器就能利用索引。

在下面的查询中索引得到了使用:

select * from employee where last_name like 'c%'

读者注意:项目真实开发中,如果经常性的模糊查询,可以采用solr或者elasticSearch或者直接Lucene也可以

4. Order by语句

ORDER BY语句决定了Oracle如何将返回的查询结果排序。

Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(联接或者附加等)。

任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。

仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。

解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。

5. NOT 的理想替代方案

我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,

也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。

下面是一个NOT子句的例子:

... where not (status ='VALID')

如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。

NOT运算符包含在另外一个逻辑运算符中,这就是不等于(<>;)运算符。

换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,

见下例:

... where status <>'INVALID'

再看下面这个例子:

;

对这个查询,可以改写为不使用NOT:

 or salary>;

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

6. IN和EXISTS(下面有个重复的)

有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。

第一种格式是使用IN操作符:

... where column in(select * from ... where ...);

第二种格式是使用EXIST操作符:

... where exists (select 'X' from ...where ...);

我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。

在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。

第二种格式中,子查询以‘select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。

这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。

相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。

通过使用EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。

Oracle系统在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。

在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。

同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高

7、Select子句中避免使用 “ * ”:

当你想在select子句中列出所有的column时,使用动态SQL列引用 ‘*' 是一个方便的方法。

不幸的是,这是一个非常低效的方法。

实际上,ORACLE在解析的过程中,会将 '*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。

8、减少访问数据库的次数:

当执行每条SQL语句时,ORACLE在内部执行了许多工作:

解析SQL语句、估算索引的利用率、绑定变量、读数据块等等。

由此可见,减少访问数据库的次数,就能实际上减少ORACLE的工作量。

举例:

题目——我要查找编号为0001、0002学生的信息。

(低效)

';
';

(高效)

';

9、使用Decode函数来减少处理时间:

使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表。

举例:

(低效)

' and name like 'anger%';
' and name like 'anger%';

(高效)

','XYZ',null)) count_02,
sum(decode(dept_id,',dept_id,null)) sum_02
from table1
where name like 'anger%';

10、整合简单,无关联的数据库访问:

如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系)

举例:

(低效)

';
';
';

(高效)

    select t1.name, t2.name, t3.name
    from table1 t1, table2 t2, table3 t3
    '

注:上面例子虽然高效,但是可读性差,需要量情而定啊!

11、删除重复记录:

最高效的删除重复记录方法 ( 因为使用了ROWID)

举例:

delete from table1 t1
where t1.rowid > (select min(t2.rowid) from table1 t2 where t1.id = t2.id); 

12、尽量不要使用having子句,可以考虑用where替换:

having只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作。

如果能通过where子句限制记录的数目,那就能减少这方面的开销。

13、尽量用表的别名:

当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个Column上。

这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。

14、用exists替换distinct:

当提交一个包含一对多表信息的查询时,避免在select子句中使用distinct. 一般可以考虑用exists替换

举例:

(低效)

select distinct d.dept_no, d.dept_name from t_dept d, t_emp e where d.dept_no = e.dept_no;

(高效)

 from t_emp where d.dept_no = e.dept_no);

exists使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.

15、用表连接替换exists:

通常来说,采用表连接的方式比exists更有效率。

举例:

(低效)

 from dept where dept_no = e.dept_no and dept_cat = 'W');

(高效)

select ename from dept d, emp e where e.dept_no = d.dept_no and dept_cat = 'W'; 

Oracle SQL调优的更多相关文章

  1. Oracle SQL 调优健康检查脚本

    Oracle SQL 调优健康检查脚本 我们关注数据库系统的性能,进行数据库调优的主要工作就是进行SQL的优化.良好的数据架构设计.配合应用系统中间件和写一手漂亮的SQL,是未来系统上线后不出现致命性 ...

  2. Oracle SQL调优记录

    目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太 ...

  3. Oracle SQL调优之分区表

    目录 一.分区表简介 二.分区表优势 三.分区表分类 3.1 范围分区 3.2 列表分区 3.3 散列分区 3.4 组合分区 四.分区相关操作 五.分区相关查询 附录:分区表索引失效的操作 一.分区表 ...

  4. Oracle SQL调优系列之SQL Monitor Report

    @ 目录 1.SQL Monitor简介 2.捕捉sql的前提 3.SQL Monitor 参数设置 4.SQL Monitor Report 4.1.SQL_ID获取 4.2.Text文本格式 4. ...

  5. Oracle SQL调优之表设计

    在看<收获,不止sql优化>一书,并做了笔记,本博客介绍一下一些和调优相关的表比如分区表.临时表.索引组织表.簇表以及表压缩技术 分区表使用与查询频繁而更新数据不频繁的情况,不过要记得加全 ...

  6. Oracle SQL 调优之 sqlhc

    SQL 执行慢,如何 快速准确的优化. sqlhc 就是其中最好工具之一 通过获得sql所有的执行计划,列出实际的性能的瓶颈点,列出 sql 所在的表上的行数,每一列的数据和分布,现有的索引,sql ...

  7. Oracle SQL调优之绑定变量用法简介

    目录 一.SQL执行过程简介 二.绑定变量典型用法 2.1.在SQL中绑定变量 2.2.在PL/SQL中使用绑定变量 2.3.PL/SQL批量绑定变量 2.4.Java代码里使用绑定变量 最近在看&l ...

  8. ORACLE SQL调优案例一则

    收到监控告警日志文件(Alert)的作业发出的告警邮件,表空间TEMPSCM2不能扩展临时段,说明临时表空间已经被用完了,TEMPSCM2表空间不够用了 Dear All:   The Instanc ...

  9. Oracle中SQL调优(SQL TUNING)之最权威获取SQL执行计划大全

    该文档为根据相关资料整理.总结而成,主要讲解Oracle数据库中,获取SQL语句执行计划的最权威.最正确的方法.步骤,此外,还详细说明了每种方法中可选项的意义及使用方法,以方便大家和自己日常工作中查阅 ...

随机推荐

  1. 轻松学习JVM——垃圾回收器

    原文链接:https://www.cnblogs.com/leefreeman/p/7402695.html 上一篇我们介绍了常见的垃圾回收算法,不同的算法各有各的优缺点,在JVM中并不是单纯的使用某 ...

  2. mfc static控件 视频播放 闪屏问题 解决方案

    方案1: 我昨天刚在csdn上解决了这个问题,不是双缓冲和WS_CLIPCHILDREN还有背景擦出什么的问题,就是在你重画的时候要去掉这些控件(按钮什么的)区域, 闪屏是因为窗口大小发生改变时,由于 ...

  3. 关于java实现断点续传的上传下载功能问题

    在web项目中上传文件夹现在已经成为了一个主流的需求.在OA,或者企业ERP系统中都有类似的需求.上传文件夹并且保留层级结构能够对用户行成很好的引导,用户使用起来也更方便.能够提供更高级的应用支撑. ...

  4. UVa 11212 Editing a Book (IDA* && 状态空间搜索)

    题意:你有一篇n(2≤n≤9)个自然段组成的文章,希望将它们排列成1,2,…,n.可以用Ctrl+X(剪切)和Ctrl+V(粘贴)快捷键来完成任务.每次可以剪切一段连续的自然段,粘贴时按照顺序粘贴.注 ...

  5. LBS 基于位置的服务

    LBS (Location Based Services)基于位置的服务 基于位置的服务,它是通过电信移动运营商的无线电通讯网络(如GSM网.CDMA网)或外部定位方式(如GPS)获取移动终端用户的位 ...

  6. (四)mysql -- 常用函数

    今天get一个,先记录一下 以后慢慢补充~ 将varchar转换成int 例如:select * from tb_1 order by cast(sport_sum as unsigned integ ...

  7. sqli-labs(12)

    0X01摘要体现(小编这里傻逼了 可以直接用group_concat函数绕过显示问题我还在用limit绕过) 还是这个模块  我们很熟徐那么先来尝试一下 单引号加入 无报错信息 哦豁 加入双引号试试呐 ...

  8. 大数据笔记(二十二)——大数据实时计算框架Storm

    一. 1.对比:离线计算和实时计算 离线计算:MapReduce,批量处理(Sqoop-->HDFS--> MR ---> HDFS) 实时计算:Storm和Spark Sparki ...

  9. vue基于element-ui的三级CheckBox复选框

    最近vue项目需要用到三级CheckBox复选框,需要实现全选反选不确定三种状态.但是element-ui table只支持多选行,并不能支持三级及以上的多选,所以写了这篇技术博文供以后学习使用. 效 ...

  10. CNN中感受野的理解

    本文摘自看完还不懂卷积神经网络“感受野”?那你来找我 作者:程序_小白链接:https://www.jianshu.com/p/9305d31962d8 一.到底什么是“感受野”(接受野Recepti ...