`

oracle-sql语句优化注意点

阅读更多
1 选择最有效率的表名顺序(只在基于规则的优化器中有效) 
	ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并. 
	例如:       
		表 TAB1 16,384 	条记录 
		表 TAB2 1       条记录 
		
	选择TAB2作为基础表 (最好的方法) 
		select count(*) from tab1,tab2;    执行时间0.96秒 
	选择TAB2作为基础表 (不佳的方法)
		select count(*) from tab2,tab1;    执行时间26.09秒 
		
	如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. 
		例如: EMP表描述了LOCATION表和CATEGORY表的交集. 
			SELECT *
			FROM LOCATION L, CATEGORY C, EMP E
			WHERE E.EMP_NO BETWEEN 1000 AND 2000
				AND E.CAT_NO = C.CAT_NO
				AND E.LOCN = L.LOCN;
				
		将比下列SQL更有效率 
			SELECT *
			FROM EMP E, LOCATION L, CATEGORY C
			WHERE E.CAT_NO = C.CAT_NO
			   AND E.LOCN = L.LOCN
			   AND E.EMP_NO BETWEEN 1000 AND 2000;
		  
2 WHERE子句中的连接顺序
	ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. 
	例如: 
		(低效,执行时间156.3秒) 
		SELECT * FROM EMP E WHERE SAL > 50000 AND JOB = ‘MANAGER’ AND 25 < (SELECT COUNT(*) FROM EMP WHERE MGR = E.EMPNO); 
		
		(高效,执行时间10.6秒) 
		SELECT * FROM EMP E WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO) AND SAL > 50000 AND JOB = ‘MANAGER’; 

3 SELECT子句中避免使用 "*"
	当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 ‘*’ 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将’*’ 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间. 
	
4 减少访问数据库的次数 
	当执行每条SQL语句时, ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等等. 由此可见, 减少访问数据库的次数 , 就能实际上减少ORACLE的工作量. 
	例如:
		以下有三种方法可以检索出雇员号等于0342或0291的职员. 
		方法1 (最低效) 
			SELECT EMP_NAME,SALARY,GRADE FROM EMP WHERE EMP_NO = 342;
			SELECT EMP_NAME,SALARY,GRADE FROM EMP WHERE EMP_NO = 291;
			
		方法2 (次低效) 
			DECLARE CURSOR C1 (E_NO NUMBER) IS 
				SELECT EMP_NAME,SALARY,GRADE FROM EMP WHERE EMP_NO = E_NO;
			BEGIN 
				OPEN C1(342); 
				FETCH C1 INTO …,..,.. ; 
				OPEN C1(291); 
				FETCH C1 INTO …,..,.. ; 
				CLOSE C1; 
			END;
			
		方法3 (高效) 
			SELECT 
				A.EMP_NAME,
				A.SALARY,
				A.GRADE,
				B.EMP_NAME,
				B.SALARY,
				B.GRADE 
			FROM
				EMP A,
				EMP B 
			WHERE A.EMP_NO = 342 AND B.EMP_NO = 291;
	注意: 
		在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200.

5 使用DECODE函数来减少处理时间
	使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表. 
	例如: 
		SELECT COUNT(*) ,SUM(SAL) FROM EMP WHERE DEPT_NO = 0020 AND ENAME LIKE ‘SMITH%’;
		SELECT COUNT(*) ,SUM(SAL) FROM EMP WHERE DEPT_NO = 0030 AND ENAME LIKE ‘SMITH%’;
		
	你可以用DECODE函数高效地得到相同结果 
		SELECT COUNT(DECODE(DEPT_NO, 0020, ’X’, NULL)) D0020_COUNT,
			   COUNT(DECODE(DEPT_NO, 0030, ’X’, NULL)) D0030_COUNT,
			   SUM(DECODE(DEPT_NO, 0020, SAL, NULL)) D0020_SAL,
			   SUM(DECODE(DEPT_NO, 0030, SAL, NULL)) D0030_SAL
		  FROM EMP
		 WHERE ENAME LIKE ‘SMITH%’;
	类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.
	
	

6 删除重复记录. 重点关注
	最高效的删除重复记录方法 ( 因为使用了ROWID) 
		DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
		
7 用TRUNCATE替代DELETE
	删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况) 
	而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. 
	(译者按: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML)

8 尽量多使用COMMIT
	只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少: 
	COMMIT所释放的资源: 
		a.回滚段上用于恢复数据的信息. 
		b.被程序语句获得的锁 
		c.redo log buffer 中的空间 
		d.ORACLE为管理上述3种资源中的内部花费 
		(译者按: 在使用COMMIT时必须要注意到事务的完整性,现实中效率和事务完整性往往是鱼和熊掌不可得兼) 
		
9 减少对表的查询
	在含有子查询的SQL语句中,要特别注意减少对表的查询.
	例如: 
	(低效) 
		SELECT TAB_NAME
		FROM TABLES
		WHERE TAB_NAME = (SELECT TAB_NAME FROM TAB_COLUMNS WHERE VERSION = 604)
		AND DB_VER = (SELECT DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
	(高效) 
		SELECT TAB_NAME
		FROM TABLES
		WHERE (TAB_NAME, DB_VER) = (SELECT TAB_NAME, DB_VER) FROM TAB_COLUMNS
		WHERE VERSION = 604)
		
	Update 多个Column 例子: 
	(低效)
		UPDATE EMP 
		SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES), 
		SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES) 
		WHERE EMP_DEPT = 0020; 
		
	(高效) 
		UPDATE EMP
		   SET (EMP_CAT, SAL_RANGE) =
			   (SELECT MAX(CATEGORY), MAX(SAL_RANGE) FROM EMP_CATEGORIES)
		WHERE EMP_DEPT = 0020;

10 用EXISTS替代IN
	在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率. 
	低效: 
		SELECT * 
		FROM EMP (基础表) 
		WHERE EMPNO >; 0 
		AND DEPTNO IN (SELECT DEPTNO 
		FROM DEPT 
		WHERE LOC = ‘MELB’);
	高效: 
		SELECT * 
		FROM EMP (基础表) 
		WHERE EMPNO >; 0 
		AND EXISTS (SELECT ‘X’ 
		FROM DEPT 
		WHERE DEPT.DEPTNO = EMP.DEPTNO 
		AND LOC = ‘MELB’) 
	(译者按: 相对来说,用NOT EXISTS替换NOT IN 将更显著地提高效率,下一节中将指出) 
	
11 用NOT EXISTS替代NOT IN
	在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历).   为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS. 
	例如: 
		SELECT * FROM EMP WHERE DEPT_NO NOT IN (SELECT DEPT_NO FROM DEPT WHERE DEPT_CAT=’A’); 
		
	为了提高效率.改写为: 
	(方法一: 高效) 
		SELECT * FROM EMP A, DEPT B WHERE A.DEPT_NO = B.DEPT(+) AND B.DEPT_NO IS NULL AND B.DEPT_CAT(+) = ‘A’

	(方法二: 最高效) 
		SELECT * FROM EMP E
		WHERE NOT EXISTS (SELECT ‘X’ FROM DEPT D WHERE D.DEPT_NO = E.DEPT_NO AND DEPT_CAT = ‘A’);
	当然,最高效率的方法是有表关联.直接两表关系对联的速度是最快的!
	
12 识别’低效执行’的SQL语句
	用下列SQL工具找出低效SQL: 
		SELECT EXECUTIONS,
			   DISK_READS,
			   BUFFER_GETS,
			   ROUND((BUFFER_GETS - DISK_READS) / BUFFER_GETS, 2) Hit_radio,
			   ROUND(DISK_READS / EXECUTIONS, 2) Reads_per_run,
			   SQL_TEXT
		  FROM V$SQLAREA
		 WHERE EXECUTIONS > 0
		   AND BUFFER_GETS > 0
		   AND (BUFFER_GETS - DISK_READS) / BUFFER_GETS < 0.8
		 ORDER BY 4 DESC;

 

分享到:
评论

相关推荐

    ORACLE-SQL性能优化大全.pdf

    - **SQL语句处理过程**:理解SQL语句在Oracle中的处理流程对于优化至关重要。 - **共享SQL区域**:Oracle会在内存的共享池中缓存已执行过的SQL语句,以便后续执行时可以直接使用而无需重新解析。 - **SQL语句处理...

    ORACLE-SQL语句优化技术分析.docx

    ORACLE SQL 语句优化技术分析 一、问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询 SQL 语句,复杂视图的编写等体会不出 SQL 语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,...

    Oracle-SQL语句(连接查询).doc

    Oracle-SQL语句(连接查询).doc

    Oracle-Sql语句资料oracle+110个常用函数经典SQL语句大全.zip

    Oracle_Sql语句资料oracle+110个常用函数经典SQL语句大全,可供学习参考。

    ORACLE-SQL性能优化(这个很全的)

    ORACLE-SQL性能优化(这个很全的),ORACLE SQL语句优化!

    ORACLE-SQL优化

    在优化SQL语句执行过程时,了解ORACLE优化器的工作机制,表之间的关联方式,以及如何获取和分析SQL执行计划是至关重要的。以下,我们将详细介绍ORACLE-SQL优化的关键知识点: 一、优化基础知识概述 优化基础知识...

    oracle-sql-select语句的使用方法.doc

    oracle-sql-select语句的使用方法.doc

    Oracle-SQL语句大全.pdf

    sql语句 Oracle_SQL语句大全.pdf

    Oracle实验二-SQL语句综合应用

    在本实验中,我们主要探讨了Oracle数据库中的SQL语句应用,涉及到了表、视图、索引以及序列等核心概念。以下是对这些知识点的详细解释: 1. **创建表**: - 使用`CREATE TABLE`语句创建了一个名为`person`的表,...

    Oracle-SQL优化.docx

    下面是 Oracle SQL 优化的相关知识点: 一、 SQL 语句编写注意问题 1.1 IS NULL 与 IS NOT NULL 在编写 SQL 语句时,需要注意 IS NULL 和 IS NOT NULL 的使用。IS NULL 用于判断某个列是否为空,而 IS NOT NULL ...

    ORACLE-SQL性能优化(内部培训资料).docx

    除了上述几点之外,还有许多其他的优化技巧可以应用于 ORACLE SQL。例如,可以使用索引、分区表、Materialized View、游标、并行查询等技术来提高性能。 此外,需要注意数据库的 Parameter 设置、系统资源的分配、...

    oracle 中SQL语句优化

    oracle中SQL语句优化

    压测Oracle的SQL语句的性能情况

    本文将深入探讨如何利用压力测试工具来评估和优化Oracle数据库中的SQL语句性能。 标题"压测Oracle的SQL语句的性能情况"暗示了我们关注的是在高负载情况下,Oracle数据库处理SQL查询的能力。压力测试(Pressure ...

    ORACLE数据库SQL语句美化器

    对ORACLE-SQL进行一些布局优化,更新它的格式

    oracle-sql优化

    SQL优化涉及多个方面,包括理解SQL语句的处理过程、Oracle优化器的工作原理、执行计划的获取与分析等。 1. **优化基础知识**:性能管理是关键,需要在系统开发初期就开始考虑,并设立明确的性能目标。调整过程中...

    Oracle Sql语句转换成Mysql Sql语句

    本项目提供了一个Java源码工具,能够帮助用户便捷地将Oracle SQL语句转换为MySQL SQL语句。 Oracle SQL与MySQL SQL的主要差异在于以下几个方面: 1. **数据类型**:Oracle支持的数据类型如NUMBER、LONG、RAW等在...

    ORACLE数据库SQL语句编写优化总结.rar

    在Oracle数据库中,SQL语句的编写和优化是数据库管理员和开发人员的重要技能。这份"ORACLE数据库SQL语句编写优化总结"文档很可能是对如何提高SQL查询性能、减少资源消耗以及提升系统整体效率的详细阐述。以下是根据...

    Oracle数据库sql语句 跟踪器

    在Oracle环境中,理解SQL语句的行为是优化数据库性能的关键。SQL Monitor提供实时视图,帮助DBA(数据库管理员)和开发人员识别性能瓶颈,改善查询效率,并确保系统的稳定运行。 SQL Monitor通过收集和展示SQL语句...

    Oracle-SQL优化.doc

    ### Oracle-SQL优化知识点详解 ...通过对Oracle优化器的选择与配置、表访问方式以及SQL语句共享机制的理解与应用,可以显著提高数据库系统的查询性能。实践中应结合具体情况灵活调整策略,以达到最佳的优化效果。

Global site tag (gtag.js) - Google Analytics