sql优化的一些方法

自己总结的一些sql优化的方法,只针对于oracle数据库,其他的数据库不一定有效。

1.访问表的方式,Oracle采用两种访问表中记录的方式:全表扫描就是顺序的访问表中每条记录,Oracle采用一次读入多个数据块的方式优化全表扫描;通过RowID访问表,采用基于rowid的访问方式,提高访问表的效率,RowID包含了表中记录的物理位置信息,Oracle采用索引Index实现了数据和存放数据的物理位置RowID之间的联系,通常索引提供了快速访问RowID的方法,因此那些基于索引列的查询就可得到性能上的提高。
2.共享SQL语句
为了不重复解析相同的sql语句,在第一次解析后,Oracle将SQL语句存放在内存中,这块位于系统全局区域的共享池中的内存可以被所有的数据库用户共享,因此,当你执行一个SQL语句,有时被称为一个游标时,如果他和之前的执行过的语句完全相同,Oracle就能很快获得已经被解析的语句以及最好的执行路径,Oracle的这个功能大大提高了SQL的执行性能并节省了内存的使用。可惜的是Oracle只对简单的表提供高速缓冲,这个功能并不适用于多表连接查询。数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越大,就可以保留更多的语句,被共享的可能性也就越大了。当你向Oracle提交一个SQL语句时,oracle会首先在这块内存中查找相同的语句。注意,Oracle对两者采取的是一种严格匹配,要达成共享,SQL语句必须完全相同,包括空格,换行等。
共享的语句必须满足三个条件:字符级的比较,当前被执行的语句和共享池中的语句必须完全相同;两个语句所指的对象必须完全相同。
3.Where字句中的连接顺序: Oracle采用自下而上的顺序解析Where字句,根据这个原理,表之间的连接必须写在其他Where条件之前,那些可以过滤掉最大数量记录的条件必须写在Where字句的末尾。
4.Select字句中避免使用‘*’
当你想在Select字句中列出所有的Column时,使用在动态SQL列引用是一个方便的方法,但是非常低效,实际上,Oracle在解析的过程中,会将依次转换成所有的列名,这个工作是通过查询数据字典完成的,这将耗费更多的时间。
5.减少访问数据库的次数
当执行每条SQL语句时,Oracle在内部执行了许多工作:解析SQL语句,估算索引的利用率,绑定变量,读数据块等,因此,减少访问数据库的次数,就能实际上减少Oracle的工作量。
6.使用Decode函数来减少处理时间:使用decode函数可以避免重复扫描相同记录或重复连接相同的表,类似的,decode函数也可以运用于Group By和Order by字句中。
7.删除重复记录
最高效的删除重复记录方法,因为使用了RowID
delete from emp e where e.rowid>(select min(x.rowid)from emp x where x.empno=e.empno);
8.用TRuncate替代Delete
当删除表中的记录时,在通常情况下,回滚段用来存放可以被恢复的信息,如果没有Commit事务,Oracle会将数据恢复到删除之前的状态,准确说是恢复到执行删除命令之前的状态,而当运用Truncate时,回滚段不再存放任何可被恢复的信息,当命令运行后,数据不能被恢复,因此很少的资源被调用,执行时间也会很短。Truncate只在删除全表适用,它是DDL,不是DML。
9.尽量多使用Commit
只要有可能,在程序中尽量多使用Commit,这样程序的性能得到提高,需求也会因为Commit所释放的资源而减少;Commit所释放的资源:回滚段上用于恢复数据的信息;被程序语句获得的锁;redo log buffer中的空间;Oracle为管理上述3种资源中的内部花费。在使用Commit时必须要注意到事务的完整性,现实中效率和事务完整性往往是不可兼得。
10.计算记录条数
和一般的观点相反,count*比count1稍快,如果可以通过索引检索,对索引列的计数仍旧是最快的。
11.用Where字句替换Having字句
避免使用Having字句,Having只会在检索出所有记录之后才对结果集进行过滤,这个处理需要排序,总计等操作,如果能通过Where字句限制记录的数目,就能减少这方面的开销。
Having中的条件一般用于对一些集合函数的比较,如count()等,除此之外,一般的条件应该写在Where字句中。
12.减少对表的查询
在含有子查询的SQL语句中,要特别注意减少对表的查询。
13.通过内部函数function提高SQL效率
14.用exists替代in
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行连接,在这种情况下,使用exists,not exists通常将提高查询的效率。相当来说,用not exists替换not in将更显著的提高效率。
15.用not exists替代not in
在子查询中,not in字句将执行一个内部的排序和合并,无论在哪种情况下,not in都是最低效的,因为它对子查询中的表执行了一个全表遍历,为了避免使用not in,我们可以改成外连接outer join或not exists.
16.用exists替换distinct
当提交一个包含一对多表信息的查询时,避免在select字句中使用distinct,一般可以考虑exists,它使查询更为迅速,因为rdbms核心模块将在子查询的条件一旦满足后,立刻返回结果。
17.用索引提高效率
索引是表的一个概念部分,用来提高检索数据的效率,实际上,oracle使用了一个复杂的自平衡B-tree结构,通常,通过索引查询数据比全表扫描要快,当oracle找出执行查询和update语句的最佳路径时,Oracle优化器将使用索引,同样在联结多个表时使用索引也可以提高效率,另一个使用索引的好处是,它提供了主键的唯一性验证。
除了那些Long或LongRaw数据类型,你可以索引几乎所有的列,通常,在大型表中使用索引特别有效,当然,在扫描小表时,使用索引同样能提高效率。
虽然使用索引能得到查询效率的提高,但是也必须注意到它的代价,索引需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身也会被修改,这意味着每条记录的insert,delete,update将为此多付出4,5次的磁盘I/O,因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。定期的重构索引是有必要的:alter indexrebuild。
18.索引的操作
Oracle对索引有两种访问模式
索引唯一扫描(index unique scan),大多数情况下,优化器通过Where字句访问index。例如,表A有两个索引,建立在列1上的唯一性索引和建立在列2上的非唯一性索引。在内部,上述SQL将被分成两步执行,首先,唯一性索引将通过索引唯一扫描的方式被访问,获得相对应的RowID,通过RowID访问表的方式执行下一步检索。如果被检索返回的列包括在index列中,Oracle将不执行第二步的处理(通过RowID访问表),因为检索数据保存在索引中,单单访问索引就可以完全满足查询结果。
索引范围查询,适用于两种情况:基于一个范围的检索;基于非唯一性索引的检索
Where字句条件包括一系列值,Oracle将通过索引范围查询的方式查询唯一性索引,由于索引范围查询将返回一组值,它的效率就要比索引唯一扫描低一些。这个SQL的执行分两步,非唯一性索引范围查询(得到所有符合条件记录的RowID)和下一步通过RowID访问表得到列1的值,由于是非唯一性索引,数据库不能对它执行索引唯一扫描。
由于SQL返回列1,而它并不存在于非唯一性索引中,所以在索引范围查询后会执行一个通过RowID访问表的操作。Where字句中,如果索引列所对应的值的第一个字符由通配符WILDCARD开始,索引将不被采用。这种情况下,Oracle将使用全表扫描。
19.基础表的选择
基础表是指被最先访问的表,通常以全表扫描的方式被访问,根据优化器的不同,SQL语句中基础表的选择是不一样的。如果使用的是CBO,优化器会检查SQL语句中每个表的物理大小,索引的状态,然后选择花费最低的执行路径。如果用的是RBO,并且所有的连接条件都有索引对应,在这种情况下,基础表就是From字句中列在最后的那个表。
20.多个平等的索引
当SQL语句的执行路径可以使用分布在多个表上的多个索引时,Oracle会同时使用多个索引并在运行时对它们的记录进行合并,检索出仅对全部索引有效的记录。在Oracle选择执行路径时,唯一性索引的等级高于非唯一性索引,然而这个规则只有当Where字句中索引列和常量比较才有效。如果索引列和其他表的索引列相比较,这种字句在优化器中的等级是非常低的。如果不同表中两个相同等级的索引将被引用,From字句中表的顺序将决定哪个会被率先使用。From字句中最后的表的索引将有最高的优先级。如果相同表中两个相同等级的索引将被引用,Where字句中最先被引用的索引将有最高的优先级。
21.等式比较和范围比较
当Where字句中有索引列,Oracle不能合并它们,Oracle将用范围比较。
22.不明确的索引等级
当Oracle无法判断索引的等级高低差别,优化器将只使用一个索引,它就是Where字句中被列在最前面的。
23.强制索引失效
如果两个或以上索引具有相同的等级,可以强制命令Oracle优化器使用其中的一个,通过他,检索出的记录数量少,这是一种相当直接的提高查询效率的办法,但是必须谨慎考虑这种策略,一般来说,只有希望单独优化几个sql时才能采用它。
24.避免在索引列上使用计算
Where字句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描。例如:select * from dept where sal*12>20000,低效率;select * from dept where sal>20000/12,高效
25.自动选择索引
如果表中有两个以上,包括两个索引,其中有一个唯一性索引,而其他是非唯一性,在这种情况下,Oracle将使用唯一性索引而完全忽略非唯一性索引。
26.避免在索引列上使用not
通常,我们要避免在索引列上使用not,not会产生在和索引列上使用函数相同的影响,当Oracle遇到not,它就会停止使用索引转而执行全表扫描。注意,在某些时候,Oracle优化器会自动将Not转化成相对应的关系操作符。
not > to <=;not>=to <等等
27.用>=替代>
两者的区别在于,前者将直接跳到第一个等于4的记录而后者将首先定位到等于3的记录并且向前扫描到第一个大于3的记录。
28.用union替换or,适用于索引列
通常情况下,用Union替换Where字句中的Or将会起到较好的效果,对索引列使用OR将造成全表扫描。注意,以上规则指针对多个索引列有效,如果有字段没有被索引,查询效率可能会因为没有选择OR而降低。
29.用in代替OR
30.避免在索引列上使用IS Null和IS NotNull
避免在索引中使用任何可以为空的列,Oracle将无法使用该索引,对于单列索引,如果列包含空值,索引中将不存在此记录,对于复合索引,如果每个列都为空,索引中同样不存在此记录。如果至少有一个列不为空,则记录存在于索引中。
31.总是使用索引的第一个列
如果索引是建立在多个列上,只有在他的第一个列被Where字句引用时,优化器才会选择使用该索引。
32.用Union-All替换Union

33.使用表的别名,可以减少解析时间并减少由于字段歧义引发的语法错误。
34.用exists代替in,因为in会对子查询的表进行全表遍历。
35.定期重构索引是有必要的。
36.用exists代替distinct。
37.sql大写,Oracle先解析sql,把小写转换成大写在执行。
38.not会使索引失效,索引列上不使用计算。
39,用>=,<=代替>,<。
40.用union代替or,这个只适用于索引列,索引列用or将会全表扫描。
41.避免在索引列使用is null,is not null,索引会失效。
42.如果索引建立在多个列上,只有他的第一个列被where子句引用时,才不会全表扫。
43.union all比union效率高,因为union要对结果集合排序,但union all将重复输出两个结果集合中的相同记录。
44.避免改变索引列的类型,比较不同类型时,Oracle会自动转换,为避免隐式转换,最好显示转换,Oracle会优先将数值类型转换成字符类型。
45.where子句中不使用索引的情况:!=;||;+;相同的索引不能互相比较。
46.特定情况下,索引会比全表扫慢。
47.避免使用耗费资源的操作,带有distinct,union,minus,interselt,orderby会启动sql引擎。
48.优化group by,将不需要的记录在group by之前过滤掉,即先查询后group by。
49.看sql执行计划,遵循最上最右原则
50.小表驱动大表
51.给频繁查询的字段上面加索引
52.使用like field%进行模糊查询
53.索引有B树索引和位图索引,唯一约束会创建唯一索引,在where中经常出现的字段用and连接的,可以创建联合索引,字段数最好不要超过3个
54.容易引起索引失效的:空值,函数字段,小表,类型隐式转换,索引列计算
55.hints:index;ordered(默认第一个表走索引);parallel(并行,orderby*2+1);first_rows(n)(查询前多少行,用于分页逐层显示,分组会忽略);rule;full;leading(table)(指定表走索引);append(插入至最后);all_rows
56.统计信息:从dba_xxx数据字典中可以查询,有个job在去自动执行(执行时间:每天22:00–6:00;周末全天)
执行命令:sql>exec dbms_stats.gather_table_stats(‘用户’,’表’);
收集统计信息:(1). select count(1) from A;=>100
2.) select table_name,num_rows from dba_tables where table_name=”;=>null/80/130
3.) exec …=>plsql complete
4.)执行2=>100
57.dba配置参数,IO,连接池,网络
58.分库分表
59.索引列不使用!=,<>,使用>
60.如果执行计划中出现merge join cartesion,就要解决笛卡尔积问题

猜你喜欢

转载自blog.csdn.net/lx_Frolf/article/details/82421855
今日推荐