版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、写出高效的SQL在多数情况下,Oracle使用索引来更快地遍历表,优化器主要根据定义的索引来提高性能。但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种SQL语句就是所谓的劣质SQL语句。在编写SQL语句时我们应清楚优化器根据何种原则来删除索引,这有助于写出高性能的SQL语句。1. IS NULL 与 IS NOT NULL避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引。 对于单列索引,如果列包含空值,索引中将不存在此记录; 对于复合索引,如果每个列都为空,索引中同样不存在此记录; 如果至少有一个列不为空,则记录存在于
2、索引中。 举例: 如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录的A,B值为(123,null), ORACLE将不接受下一条具有相同A,B值(123,null)的记录(插入), 然而如果所有的索引列都为空,ORACLE将认为整个键值为空而空不等于空。 因此你可以插入1000 条具有相同键值的记录,当然它们都是空! 因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引。不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值
3、,即使对该列建索引也不会提高性能。任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。注意:如果我们必须要用 is null,又需要提供查询效率 可以用函数索引实例如下:create table test_date (name varchar2(20),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) value
4、s (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) = NSELECT STATEMENT, GOAL = CHOOSE TABLE ACCESS FULL Object owner=SP2 Object name=TEST_DATE 注意 要使用cost 才会使用fu
5、nction index1 / 8analyze table test_date compute statistics for table for all indexes for all indexed columns; select * from test_date a where decode(day,null,N,Y) = NSELECT STATEMENT, GOAL = CHOOSE Cost=1 Cardinality=1 Bytes=11TABLE ACCESS BY INDEX ROWID Object owner=SP2 Object name=TEST_DATE Cost=
6、1 Cardinality=1 Bytes=11 INDEX RANGE SCAN Object owner=SP2 Object name=FINX_DAY Cost=2 Cardinality=1 2. 联接列对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。我们一起来看一个例子,假定有一个职工表(employee),对于一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。下面是一个采用联接查询的SQL语句,select * from employs where first_name|
7、|last_name =Beill Cliton上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。当采用下面这种SQL语句的编写,Oracle系统就可以采用基于last_name创建的索引。Select * from employee wherefirst_name =Beill and last_name =Cliton遇到下面这种情况又如何处理呢?如果一个变量(name)中存放着Bill Cliton这个员工的姓名,对于这种情况我们又如何避免全程遍历,使用索引呢?可以使用一个函数,将变量name中的姓和名
8、分开就可以了,但是有一点需要注意,这个函数是不能作用在索引列上。下面是SQL查询脚本:select * from employeewherefirst_name = SUBSTR(&name,1,INSTR(&name, )-1)andlast_name = SUBSTR(&name,INSTR(&name, )+1)注:substr和instr用法1)、substr(string string, int a, int b) 参数1:string 要处理的字符串 参数2:a 截取字符串的开始位置(起始位置是0) 参数3:b 截取的字符串的长度(而不是字符串的结束位置) 例如: substr(A
9、BCDEFG, 0); /返回:ABCDEFG,截取所有字符 substr(ABCDEFG, 2); /返回:CDEFG,截取从C开始之后所有字符 substr(ABCDEFG, 0, 3); /返回:ABC,截取从A开始3个字符 substr(ABCDEFG, 0, 100); /返回:ABCDEFG,100虽然超出预处理的字符串最长度,但不会影响返回结果,系统按预处理字符串最大数量返回。 substr(ABCDEFG, 0, -3); /返回:EFG,注意参数-3,为负值时表示从尾部开始算起,字符串排列位置不变。 2)、instr的语法如下:instr( string1, string2
10、, start_position , nth_appearance )函数说明:该函数返回参数string2在参数string1中的位置。start_position参数表示将从string1的第几个字符开始来查找string2。该参数为可选参数,如果省略,那么默认为1。instr函数默认的查找顺序为从左到右。当该参数为负数的时候,则从右边开始查找。nth_appearance表示返回第几次出现的string2的位置。该参数为可选参数,如果省略则默认为1,也就是返回首次出现string2的位置。示例:SELECT INSTR(CORPORATE FLOOR, OR, -1, 1) “aaa”
11、FROM DUAL;aaa-143. 带通配符(%)的like语句同样以上面的例子来看这种情况。目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句:select * from employee where last_name like %cliton%这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引。在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用:select * from employee
12、where last_name like c%4. Order by语句ORDER BY语句决定了Oracle如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。5. NOT 的理想替代方案我们在查询时经常在where子句使用一些逻辑表达式,如大于
13、、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子:. where not (status =VALID)如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(;)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例:. where status INVALID再看下面这个例子:select * from employee where salary3000;对这个查询,可以改写为不使用N
14、OT:select * from employee where salary;3000;虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。6. IN和EXISTS(下面有个重复的)有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。第一种格式是使用IN操作符:. where column in(select * from . where .);第二种格式是使用EXIST操作符:. where exists (select X
15、from .where .);我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。第二种格式中,子查询以select X开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。通过使用EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节
16、省了时间。Oracle系统在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高7、Where子句中的连接顺序: (CBO根据对表做的分析进行执行,RBO根据索引)ORACLE采用自下而上的顺序解析WHERE子句。 根据这个原理,表之间的连接必须写在其他WHERE条件之
17、前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。注:RBO CBO 模式Oracle的优化器有两种优化方式,即基于规则的优化方式(Rule-Based Optimization,简称为RBO)和基于代价的优化方式(Cost-Based Optimization,简称为CBO),在Oracle8及以后的版本,Oracle强列推荐用CBO的方式RBO方式:优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则。比如我们常见的,当一个where子句中的一列有索引时去走索引。CBO方式:它是看语句的代价(Cost),这里的代价主要指Cpu和内存。优化器在判断是否用这种方
18、式时,主要参照的是表及索引的统计信息。统计信息给出表的大小、有少行、每行的长度等信息。这些统计信息起初在库内是没有的,是做analyze后才出现的,很多的时侯过期统计信息会令优化器做出一个错误的执行计划,因些应及时更新这些信息。Examda提示:主索引不一定就是优的,比如一个表只有两行数据,一次IO就可以完成全表的检索,而此时走索引时则需要两次IO,这时全表扫描(full table scan)是最好优化模式包括Rule、Choose、First rows、All rows四种方式:Rule:基于规则的方式。Choolse:默认的情况下Oracle用的便是这种方式。指的是当一个表或或索引有统计
19、信息,则走CBO的方式,如果表或索引没统计信息,表又不是特别的小,而且相应的列有索引时,那么就走索引,走RBO的方式。First Rows:它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快的方式返回查询的最先的几行,从总体上减少了响应时间。All Rows:也就是我们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返回表的所有的行,从总体上提高查询的吞吐量。没有统计信息则走RBO的方式。设定选用哪种优化模式:A、Instance级别我们可以通过在initSID.ora文件中设定OPTIMIZER_MODE=RULE/CHOOSE/FIRST_ROWS/AL
20、L_ROWS如果没设定OPTIMIZER_MODE参数则默认用的是Choose方式。B、Sessions级别通过ALTER SESSION SET OPTIMIZER_MODE=RULE/CHOOSE/FIRST_ROWS/ALL_ROWS来设定。C、语句级别用Hint(/*+ . */)来设定为什么表的某个字段明明有索引,但执行计划却不走索引?1、优化模式是all_rows的方式2、表作过analyze,有统计信息(最可能的就是统计信息有误)3、表很小,上文提到过的,Oracle的优化器认为不值得走索引。我们可以查看一下一个表或索引是否是统计信息SELECT * FROM user_tabl
21、esWHERE table_name=AND num_rows is not null;SELECT * FROM user_indexesWHERE table_name=AND num_rows is not null;当我们使用CBO的方式,就应当及时去更新表和索引的统计信息,以免生形不切合实的执行计划。ANALYZE table table_name COMPUTE STATISTICS;ANALYZE INDEX index_name ESTIMATE STATISTICS;8、Select子句中避免使用 “ * ”: 当你想在select子句中列出所有的column时,使用动态SQ
22、L列引用 * 是一个方便的方法。 不幸的是,这是一个非常低效的方法。 实际上,ORACLE在解析的过程中,会将 * 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。9、减少访问数据库的次数: 当执行每条SQL语句时,ORACLE在内部执行了许多工作: 解析SQL语句、估算索引的利用率、绑定变量、读数据块等等。 由此可见,减少访问数据库的次数,就能实际上减少ORACLE的工作量。 举例: 题目我要查找编号为0001、0002学生的信息。 (低效) select name,age,gender,address from t_student where id =
23、 0001; select name,age,gender,address from t_student where id = 0002; (高效) select ,a.age,a.gender,a.address,,b.age,b.gender,b.address from t_student a,t_student b where a.id = 0001 and b.id = 0002;10、使用Decode函数来减少处理时间: 使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表。 举例: (低效) select count(*), sum(banace
24、) from table1 where dept_id = 0001 and name like anger%; select count(*), sum(banace) from table1 where dept_id = 0002 and name like anger%; (高效) select count(decode(dept_id,0001,XYZ,null) count_01,count(decode(dept_id,0002,XYZ,null) count_02, sum(decode(dept_id,0001,dept_id,null) sum_01,sum(decode(
25、dept_id,0002,dept_id,null) sum_02 from table1 where name like anger%;11、整合简单,无关联的数据库访问: 如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系) 举例: (低效) select name from table1 where id = 0001; select name from table2 where id = 0001; select name from table3 where id = 0001; (高效) select , , from table1 t1, table2 t2, table3 t3 where t1.id(+) = 0001 and t2.id(+) = 0001 and t3.id(+) = 0001 注:上面例子虽然高效,但是可读性差,需要量情而定啊!12、删除重复记录: 最高效的删除重复记录方法 ( 因为使用了ROWID) 举例: delete from table1 t1 where t1
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年度中医妇科师承教育合作合同4篇
- 2025年度智能化生产线设备采购合同补充协议3篇
- 2024进出口业务销售合同范本
- 2025不锈钢水箱售后服务与维护保养合同范本3篇
- 2024版潜孔钻租赁业务协议要约一
- 家用电烤盘建设项目申请报告可行性研究报告
- 2025年度智能驾驶技术研发中心高级工程师个人聘用合同3篇
- 2025年度个人抵押贷款合同终止及债权债务处理合同范本4篇
- 2025年度个人消费信贷融资委托服务协议3篇
- 2025年宁夏公路桥梁建设有限公司招聘笔试参考题库含答案解析
- GB/T 12914-2008纸和纸板抗张强度的测定
- GB/T 1185-2006光学零件表面疵病
- ps6000自动化系统用户操作及问题处理培训
- 家庭教养方式问卷(含评分标准)
- 城市轨道交通安全管理课件(完整版)
- 线缆包覆挤塑模设计和原理
- TSG ZF001-2006 安全阀安全技术监察规程
- 部编版二年级语文下册《蜘蛛开店》
- 锅炉升降平台管理
- 200m3╱h净化水处理站设计方案
- 个体化健康教育记录表格模板1
评论
0/150
提交评论