Oracle性能优化之四个方面

想要优化Oracle的性能 就要从以下四个方面做起

  1. 不要让Oracle做的太多
  2. 给优化器更明确的命令
  3. 减少访问次数
  4. 细节上的影响

目录

1. 不要让Oracle做的太多

避免复杂的多表关联

避免使用 星号 “*”

避免使用耗费资源的操作

2. 给优化器更加明确的命令

自动选择索引

至少要包含组合索引的第一列

避免在索引列上使用函数

避免使用前置通配符

避免在索引列上使用NOT

避免在索引列上使用IS NULL 和IS NOT NULL 

避免出现索引列自动转换

在查询时尽量少用格式转换

3. 减少访问次数

减少访问数据库的次数

使用DECODE来减少处理时间

减少对表的查询

4. 细节上的影响

where子句中的连接顺序

WHERE子句中的函数和表达式的使用

ORDER BY语句

联接列

用WHERE子句替换HAVING子句

用 NOT EXSITS替代NOT IN

通过使用>=、<=等,来避免使用NOT命令

尽量多使用COMMIT


1. 不要让Oracle做的太多

避免复杂的多表关联

复杂的多表关联很难优化,而且随着数据量的增加,性能风险也在增加。

避免使用 星号 “*”

使用 星号*是一个非常方便但是又很低效的方法。事实上,Oracle在解析的过程中会将星号*一次转换成多有列名,这个工作是通过查询数据字典完成的,这意味着耗费更多的时间。

因此,最好的办法就是只提取要使用的列,而且使用列别名能够加快解析速度

避免使用耗费资源的操作

带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的sql语句会启动sql引擎执行耗费资源的排序功能。DISTINCT需要一次排序操作,但是其他的至少需要执行两次。

例如,一个UNION查血,其中每个查询都带有GROUP BY的子句,GROUP BY 会触发嵌入排序(NESTED SORT)。因此每个查询需要执行一次排序,然后在执行UNION时,另一种排序——唯一排序(SORT UNIQUE)操作也需要被执行,但是它只能等待前面的嵌入排序结束后才能开始执行。因此嵌入排序的深度大大的影响查询效率。

通常,带有DISTINCT,UNION,MINUS,INTERSECT的SQL语句都可以用其他方式重写

比如,用EXISTS替换DISTINCT

--低效
SELECT DISTINCT dept_no,dept_name
FROM dept D, emp E
WHERE D.dept_no=E.dept_no

--高效
SELECT dept_no,dept_name
FROM dept D
WHERE EXISTS(
    SELECT 1
    FROM emp E
    WHERE E.dept_no=D.dept_no
)

用UNION ALL 替换 UNION:

当sql语句需要取两个查询结果集合的并集时,使用UNION ALL并对最后输出结果排序会更加高效。

2. 给优化器更加明确的命令

自动选择索引

如果表中有两个及以上的索引,其中有一个唯一性索引,而其他是普通索引时,Oracle将使用唯一索引检索记录而户数普通索引。

至少要包含组合索引的第一列

如果索引是建立在多个列上,只有在他的第一个列被where子句引用时,优化器才会选择使用该索引。当引用索引的第二列及以后时,优化器选择全表扫描而忽略了索引。

避免在索引列上使用函数

where子句中,如果索引列是函数的一部分,优化器将不使用索引而采用全表扫描。列:

--低效
SELECT ...
FROM dept
WHERE sal*12 > 25000;

--高效
SELECT ...
FROM dept
WHERE sal > 25000/12;

避免使用前置通配符

where子句中,如果索引列所对应的值的第一个字符由通配符开始,索引将不被采用。例:

SELECT user_no,user_name
FROM users
WHERE user_no LIKE '%109204421';

此时,Oracle将使用全表扫描。

避免在索引列上使用NOT

同上,当在索引列上使用NOT时就会停止使用索引而转为执行全表扫描。

避免在索引列上使用IS NULL 和IS NOT NULL 

首先,要避免在索引中使用任何可以为空的列,Oracle将无法使用该索引。对于单列索引,如果列值包含空值,索引中将不存在此记录;对于复合索引,如果每个列都为空,索引中同样不存在此记录,当然如果至少一个列不为空,则该记录存在于索引中。

所以,因为空值不存在与索引列中,所以where子句中如果对索引列进行空值比较的话,Oracle会停用该索引。

避免出现索引列自动转换

当比较不同数据类型的数据时,Oracle自动对列进行简单的类型转换。比如 emp_type是一个字符串类型的索引列。当它和一个数字进行比较时,会被转为数值型。这时候由于内部发生类型转换,所以这个索引将不会被用到。

在查询时尽量少用格式转换

--如用
WHERE a.order_no = b.order_no

--不用
WHERE TO_NUMBER (substr(a.order_no, instr(b.order_no, '.') - 1) 
= TO_NUMBER (substr(a.order_no, instr(b.order_no, '.') - 1)
 

3. 减少访问次数

减少访问数据库的次数

使用DECODE来减少处理时间

减少对表的查询

4. 细节上的影响

where子句中的连接顺序

Oracle采用自下而上的顺序解析where子句,根据这个原理,当在where子句中有多个表连接时,where子句中排在最后的表应当是返回行数可能最少的表,有过滤条件的子句应当放在where子句的最后。例:如歌dept表返回的记录较多的话,上的sql语句会比下面的快很多

SELECT * FROM emp e,dept d 
	WHERE d.deptno >10 AND e.deptno =30 ; 

SELECT * FROM emp e,dept d 
	WHERE e.deptno =30 AND d.deptno >10 ;

WHERE子句中的函数和表达式的使用

最好不要在where子句中使用函数或者表达式,如果要使用的话,最好统一使用相同的表达式或函数,这样便于以后使用合理的索引。

ORDER BY语句

任何在ORDER BY语句的非索引项或者有计算表达式都将降低查询速度。因此,仔细检查ORDER BY语句以以找出非索引项或者表达式,它们会降低性能。 解决这个问题的办法就是重写ORDER BY语句以使用索引,也可以为这些非索引列创建索引,同时应避免在 ORDER BY子句中使用表达式。

联接列

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

SELECT * FROM employss 
WHERE first_name||''||last_name ='Beill Cliton'; 

系统优化器对基于last_name创建的索引没有使用,当采用下面这种sql语句时,Oracle就会使用基于last_name创建的索引

SELECT * FROM employee  
WHERE first_name ='Beill' AND last_name ='Cliton'; 

用WHERE子句替换HAVING子句

避免过度使用HAVING子句,因为HAVING子句只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序统计等操作。如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销。

用 NOT EXSITS替代NOT IN

在子查询中,NOT IN 子句将执行一个内部的排序和合并。因此无论在哪种情况下,NOT IN都是最低效的(因为它对子查询中的表执行了全表遍历)。因此尽量使用NOT EXISTS来代替NOT IN可以提高效率,例:

--语句1 

SELECT dname, deptno FROM dept WHERE 
	deptno NOT IN (SELECT deptno FROM emp); 

--语句2 

SELECT dname, deptno FROM dept WHERE 
	NOT EXISTS 
    (SELECT deptno FROM emp WHERE dept.deptno = emp.deptno); 

其中语句2的性能比1好很多。因为1中对emp进行了全表扫描,且没有用到索引,因为没有where子句。而2中的语句对emp进行了缩小范围的查询。

通过使用>=、<=等,来避免使用NOT命令

--语句1
SELECT * FROM employee WHERE salary <>3000

--语句2
SELECT * FROM employee WHERE salary<3000 OR salary>3000 

sql语句2要比1更快一些,因为第二个运行Oracle对salary列使用索引,但是1由于存在not就不能使用索引。

尽量多使用COMMIT

commit 可以释放资源。

发布了36 篇原创文章 · 获赞 3 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tyro_blog/article/details/103011627
今日推荐