Oracle 11g_优化SQL语句(13)

1.常规SQL语句优化

应用系统的性能优化包括对SQL语句,Oracle系统,操作系统等的调整。其中工作量最大的就是SQL语句的调整。

1.1 建议不用 "*" 来代替所有列名

SELECT语句中可以用"*"来列出某个表的所有列名,但是这样的写法对Oracle系统来说存在解析的动态问题。Oracle系统会通过查询数据字典来将 "*" 转换成表的所有列名,这自然会消耗系统时间。建议用户在写SELECT语句时,采用与访问表有关的实际列名。

1.2 用TRUNCATE 代替 DELETE

当使用DELETE删除表中的数据时,Oracle会使用撤销表空间(UNDO TABLESPACE)来存放恢复的信息。在这期间,如果用户没有发出COMMIT命令,而是发出ROLLBACK命令,Oracle系统会将数据恢复到删除之前的状态。
    当用户使用 TRUNCATE 语句对表的数据进行删除时,系统不会将被删除的数据写到回滚段(或撤销空间)中,速度当然要快得多。所以希望对表或者簇中的所有行全部删除时,采用TRUNCATE命令更加有效,其语法格式如下:

TRUNCATE [TABLE | CLUSTER] schema.[table_name][cluster_name][DROP | REUSE STORAGE]
table_name: 要清空的表明。
cluster_name: 要清空的簇名。
DROP | REUSE STORAGE: 表示保留被删除的空间以供该表的新数据使用或回收空间,默认为DROP STORAGE,
即收回被删除的空间系统。

在 SQL*Plus 环境下,直接采用TRUNCATE TABLE命令即可,若要在PL/SQL中使用,只能采用动态语句实现。

**** 创建一个存储过程,实现使用TRUNCATE命令动态删除数据表,代码:

SQL> create or replace procedure trun_table(table_deleted in varchar2) as		-- 实现清空指定的表
		cur_name integer;		-- 定义内部变量,存储打开的游标
	begin
		cur_name:=dbms_sql.open_cursor;	-- 打开游标
		
		/* 执行truncate table table_deleted命令,从而清空指定的表 */
		dbms_sql.parse(cur_name,'truncate table'||table_deleted||'drop storage',dbms_sql.native);
		dbms_sql.close_cursor(cur_name);
	exception
		when others then dbms_sql.close_cursor(cur_name);
		raise;
	end trun_table;
	/

	过程已创建。

1.3 在确保完整性的情况下多用COMMIT语句

在PL/SQL块中,经常将几个相互关联的DML语句写在一个BEGIN...END块中,建议在每个块的END前面使用COMMIT语句,这样就可以实现对象DML语句的及时提交,同时也释放事务所占的用的资源。

	COMMIT语句所释放的资源如下:

	** 回滚段上用于恢复数据的信息,撤销表空间也只做短暂的保留。
	** 被程序语句获得的锁。
	** 重做日志缓冲区(Redo Log Buffer)中的空间。
	** Oracle为管理上述资源的内部花费。

1.4 尽量减少表的查询次数

在含有子查询的SQL语句中,要特别注意减少对表的查询,代码:

	第一种:低效率的SQL查询语句。
	SQL> select empno,ename,job from emp
		where deptno in (select deptno from dept where loc='BEIJING')
		or deptno in (select deptno from dept where loc='NEW YORK');

	第二种:对上面的代码进行适当修改,高效率的SQL查询语句如下:
	SQL> select empno, ename, job from 
		where deptno in(select deptno from dept where loc='BEIJING' OR loc='NEW YORK');

在第一种查询语句中,要对dept表执行两遍查询,而在第二种查询中,仅对dept表执行一遍查询。在大量数据的情况下,显然第二种查询要比第一种查询快得多。

1.5 用[NOT] EXISTS代替[NOT] IN

在子查询中,[NOT] IN子句将执行一个内部的排序与合并,无论在哪种情况下,[NOT] IN语句都是最低效的,因为它对子查询中的表执行了一个全表遍历。为了避免使用[NOT] IN,用户可以把它改成外连接(Outer Joins),NOT EXISTS或者EXISTS子句,代码:

第一种:低效率的NOT IN子句
SQL> select empno,ename,from emp
		where empno not in(select deptno from dept where loc='BEIJING');

第二种:高效率的EXISTS子句
SQL> select empno,ename from emp
		where exists(select deptno from dept where loc!='BEIJING');

在SQL语句中,很多资料都建议最好不用[NOT] IN。那么,[NOT] IN在何处可以用呢?这里要一分为二地看[NOT]IN,即当[NOT]IN后面跟子查询,并且查询地结果较多时,不宜使用[NOT]IN;但如果[NOT]IN后面地括号内是列表(可枚举的几个)或子查询所满足地结果集很小时,也是可以使用的。

2. 表连接优化

在关系数据库中,各表之间存在一定地关系。无论在数据库中采用哪种优化模式运行,在SQL语句中表的连接方法都可能对性能产生很大的影响。

2.1 驱动表的选择

驱动表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问)。Oracle 11g优化器会检查SQL语句中的每个表的物理大小,索引状态,然后选用花费最低的执行路径。

*** 从Students表和Department表查询学生信息,代码:
	SQL> select s.Name,d.Dept_Name
		from Department d, Students s
		where d.Dept_No=s.Dept_No;

从上面的代码中,假设在Students表的dept_no列创建索引,而在Department表的dept_no列没有索引。
由于Department最先被访问(紧跟FROM其后),这样Department表将被作为查询中的驱动表,由此可见,只有两个表都建立索引,优化器才能按照紧随FROM关键字后面的为驱动表的规则来对待。

2.2 WHERE子句的连接顺序

    Oracle采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其它WHERE条件之前。

    那些可以过滤最大数据记录的条件必须写在WHERE子句的末尾,也就是在表进行连接操作之前,过滤到的记录越多越好。

3. 合理使用索引

创建主键和唯一索引的主要目的除了数据的完整性和一致性之外,还具有提高查询速度的作用。此外,创建一般索引的目的就是为了提高查询速度。

3.1 何时使用索引

在利用索引的情况下,由于只从表中选择部分行,所以能够提高查询速度。对于只从总行数中查询2%~4%的表,可以考虑创建索引。下面是创建索引的基本原则:

    (1)已查询关键字为基础,表中的行随机排序。
	(2)包含的列数相对比较少的表。
	(3)表中的大多数查询都包含相对简单的WHERE从句。
	(4)经常以查询关键字为基础的表,并且该表中的行遵从均匀分布。
	(5)缓存命中率低,并且不需要操作系统权限。

3.2 索引列和表达式的选择

在创建索引时,选择列和表达式是非常重要的,下面是创建索引时选择索引列的原则:
 

	(1)WHERE从句频繁使用的关键字。
	(2)SQL语句中频繁使用进行表连接的关键字。
	(3)可选择性高(重复性少的)关键字。
	(4)对于取值较少的关键字或表达式,不要采用标准的B树索引,可以考虑建立位图索引。
	(5)不要将那些频繁修改的列作为索引列。
	(6)不要使用包含操作符或函数的WHERE从句中关键字作为索引列,如果需要的话,可以考虑建立函数索引。
	(7)如果大量并发的INSERT, UPDATE, DELETE语句访问了父表或者子表,则考虑使用完整性约束的外部键作为索引。
	(8)在选择索引列时,还要考虑该索引所引起的INSERT, UPDATE, DELETE操作是否值得。

3.3 选择复合索引列

多列索引也叫作复合索引,复合索引有时比单列索引有更好的性能。如果在建立索引时采用了几个列作为索引,则在使用时也要按照建立时的顺    序来描述,也就是说,主列是最先被选择的列。

     
    **** 为tb_test表创建一个复合索引complex_index,该索引包括column1, column2, column3列(并且建立顺序亦如此),如果把这3列作为WHERE查询条件,那么这3个列作为WHERE查询条件,那么这3个列的最优排序方式,如下:

SQL> create index complex_index on tb_test(column1,column2,column3)

	索引已创建。

	SQL> select* from tb_test where column1>0 and column2>0 and column3<0

	这里的索引complex_index是一个复合索引,它包含column1, column2, column3三个列。由于本索引被建立成复合型,所以在查询语句中要带有WHERE...AND从句才能使用该复合索引。
在选择复合索引的关键字时,要遵循下列的原则:

	(1)如果某些关键字在WHERE从句中的使用频率较高,则考虑创建索引。
	(2)如果某些关键字在WHERE从句中的使用频率相当,则创建索引时考虑按照从高到低的顺序来说明关键字。
	(3)如果几个查询都选择相同的关键字集合,则考虑创建组合索引。
	(4)创建索引以后使得WHERE从句所使用的关键字能够组成前导部分。
	(5)应该选择在WHERE从句条件中频繁使用的关键字,并且这些关键字由AND操作符连接。

3.4 避免全表扫描大表

在应用程序中,除了一些必要的情况,如统计月报数据,打印所有清单等任务可以允许使用全表扫描外,一般都应尽量避免对大表进行全表扫描。全表扫描是指不加任何条件或没有使用索引的查询语句。一些情况Oracle可以使用全表扫描。

    (1)所查询的表没有索引。
	(2)需要返回所有的行。
	(3)带LIKE并使用'%'这样的语句就是全表扫描。
	(4)对索引主列有条件的限制,但使用了函数,则Oracle使用全表扫描,代码:
		SQL> select * from emp where substr(ename,1,1)='M';

	(5)带有IS NULL, IS NOT NULL 或 !=等子句也导致全表扫描,代码: 
		SQL> select * from emp where job!='MANAGER';

3.5 监视索引是否被使用

除了主键是完整性约束而自动变为索引外,创建普通索引的目的就是为了提高查询速度。如果我们创建了索引而索引没有被使用,那么这些不被使用的索引将起到阻碍性能的作用。

为了辨别索引是否被使用,从Oracle 9i 版本开始,用户可以对索引进行监视,通常使用ALTER INDEX...MONITORING USAGE语句,其具体语法格式如下:

ALTER INDEX schema.index_name MONITORING USAGE;
**** 监视学生成绩表studentgrade的grade_index索引是否被使用,步骤及代码:


(1)设置监视索引grade_index,代码:
SQL> alter index grade_index monitoring usage;

索引已更改。

(2)检查索引使用情况
SQL> select * from v$object_usage;


(3)在第2步检查中,如果发现索引grade_index在限定的时间内得不到使用(即USE列的值为NO),则建议使用DROP INDEX语句删除掉,代码:
SQL> drop index grade_index;

4. 优化器的使用

Oracle优化器(Optimizer)的使用方法,是程序员对应用程序优化时的检查工具。


4.1 优化器的概念

尽管现在计算机的CPU速度达到GB级,但在处理数据库时还是显得不够。在大型应用系统中,存在许多消耗CPU大量时间的SQL语句,但是却很少被程序员本人发现。

实际上,Oracle优化器在处理每一个SQL语句准备执行之前,都需要进行许多步骤才能使SQL语句成为可执行的语句。

(1)语法检查:检查SQL语句的拼写是否正确。
(2)语义分析:核实所有与数据字典不一致的表和列的名称。
(3)概要存储检查:检查数据字典,以确定该SQL语句的概要是否已经存在。
(4)生成执行计划:使用基本成本优化规则和数据字典的统计表来决定最佳执行计划。
(5)建立二进制代码:基于执行计划,Oracle生成了二进制执行代码。

为了使每条SQL语句的性能能达到优化,建议用户对所有的SQL语句执行EXPLAIN PLAN命令,并查看输出结果,然后对性能低下的SQL语句进行调整。

通过设置执行计划(即:EXPLAIN PLAN命令),可以了解Oracle在执行SELECT, DELETE, INSERT, UPDATE语句时的情况。所谓SQL语句执行计划就是Oracle优化器在执行每个SQL语句时所采用的执行顺序。执行计划包括以下的几个方面。

A. 语句所引用的表的顺序。
B. 语句所涉及的表的访问方法。
C. 语句中连接操作所影响的各表的连接方法。

Oracle 11g 数据库在执行SQL语句时,都是使用基于代价(或者成本)的优化器--这个代价(或者成本)就是指占用一定的系统资源。

4.2 运行EXPLAIN PLAN

执行计划是Oracle系统在执行SQL语句时的一种执行策略。那么用户如何看到这些执行计划的内容呢?

为了得到Oracle产生的执行计划的报告,必须创建一个表来存放系统检查SQL语句执行计划时所产生的结果,建议在用户的帐户下执行UTLXPLAN脚本来完成plan_table表的创建,该表存放执行计划的信息。

当运行了UTLXPLAN.SQL这个脚本后,Oracle在用户的帐户下创建了table_name表。该表用于存放用户希望产生的SQL语句的执行计划。那么,如何才能使系统生成某个SQL语句的执行计划呢?这就是EXPLAIN PLAN命令的工作,其语法格式如下:

EXPLAIN PLAN [SET statement_id [=] <string literal>]
[INTO <table_name>]
FOR <sql_statment>

4.3 Oracle 11g中SQL执行计划的管理

Oracle在执行一个SQL之前,首先要分析以下语句的执行计划,然后再按执行计划去执行。分析语句执行计划的工作是由优化器(Optimizer)来完成的。不同的情况下,一条SQL语句可能有多种执行计划,但在某一时刻,一定只有一种计划是最优的,花费时间是最少的。

Oracle 11g使用基于代价的优化方式(Cost_Based Optimization, CBO),这里的代价主要指CPU和内存,优化器主要参照的是表及索引的统计信息。

统计信息给出表的大小,有多少行,每行的长度等信息。

这些统计信息起初在数据库内是没有的,是用户在做ANALYZE(统计分析)后才发现的。很多时候,过期统计信息会令优化器做出一个错误的执行计划,因此用户应及时更新这些数据。

说明:不一定用索引就是最优的,例如一个表只有两行数据,一次IO就可以完成全表的检索,而此时用索引,则需要两次IO,这时对这表做全表扫描就是最优的。

5. 数据库和SQL重演

对于数据库和SQL语句的优化,Oracle 11g提出了一个新特性---那就是数据库重演(Database Replay)和SQL重演(SQL Replay)。

5.1 数据库重演

数据库重演(Database Replay)是指产品环境的数据库上捕捉所有负载,并可以将之传至备份的(Standby)数据库或有备份恢复的测试库上,在测试环境中重演主库的环境,这使得升级或软件更新可以进行预先的"真实"测试,或者可以通过测试环境完全再现真实环境的负载及运行情况。

这是Oracle向后追朔能力的又一增强,在Oracle 10g中,我们知道Oracle通过v$session_wait_history视图,ASH特性等,实现将数据库的等待时间向后追溯。现在通过Database Replay特性,Oracle可以将整个数据库的负载捕获,记录并实现Replay,,也就是增强了整个数据库的向后追朔的能力。

这一特性提供了再现现场能力,极大地丰富了用户发现并解决数据库问题的手段,将为数据库管理带来更多的方便。

当然使用这一特性会带来一定的性能负担,Oracle说这一负担在5%左右。

5.2 SQL重演

    数据库重演的简化版本就是SQL重演(SQL Replay),即只捕获SQL负载,通过SQL负载,应用程序可以再现SQL负载。


6. Oracle的性能顾问

Oracle 数据库中有一个自动数据库诊断监控程序(ADDM)形式的助理DBA,这种机器人式的DBA会不知疲倦地反复搜索数据库系统统计,以标识瓶颈,分析SQL语句,并据此提供多种改进性能的建议。

Oracle自动SQL调整解决方案包括SQL调优顾问(SQL Tuning Advisor)和SQL访问顾问(SQL Access Advisor),可以为应用程序提供综合,自动,具有成本效益的解决方案,减少SQL的调整时间和管理成本。

6.1 SQL调优顾问

SQL调优顾问(SQL Tuning Advisor)是Oracle 10g中引入的,设计它的目的就是为了替代传统的手工SQL调整。SQL调优顾问处理的对象包括那些响应时间很慢或者是占用CUP/Disk很高的SQL。SQL调优顾问收集这些SQL,并且给出自己的建议,它包括下面的部分。
(1)怎样优化SQL的执行计划。
(2)优化后效率的提升幅度。
(3)做出这条建议的理论原理。
(4)直接给出推荐使用的命令。

用户可以有选择性地接收这些建议,然后去调优SQL。随着SQL调优顾问地引入,用户现在就可以让Oracle优化器来自动调整SQL。

6.2 SQL访问顾问

SQL访问顾问(SQL Acess Advisor)地设计目的是获得实际频率和使用类型(而非数据类型)进行分区,索引和创建物化视图以改进模式设计的建议。这与SQL Tuning Advisor提供有关查询,调整及在流程中延长整个优化过程的建议有所不同,它的特点如下:

(1)分析整个负载而不仅仅是单独的SQL语句。
(2)使访问结构设计更加清晰,以优化应用程序性能。
(3)建议创建和删除某些索引,物化视图和物化视图日志以提高性能。

Oracle 11g的SQL访问顾问除了可以像在Oracle 10g中一样分析索引,物化视图等,还可以分析表和查询以识别可能的分区策略,这在进行最佳模式设计时可以提供很大的帮助。在Oracle 11g中,SQL访问顾问可以提供与整个负载有关的建议,包括考虑创建成本和维护访问结构等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值