sql执行计划
SQL执行计划与数据库性能(图片粘不过来)
l 什么因素影响数据库性能
一个数据库性能好不好,作为客户,他的评价标准只有一个:那就是系统用起来感觉快不快。到底影响系统性能的因素在哪些方面?通常我们按照不同的标准按照影响的大小划分为:
|
硬件
数据库
应用设计
|
出现性能问题,通常看起来最直接最简单的办法就是升级硬件,加内存,加CPU。但是大量的事实却告诉我们,这样做最性能的提高的比例很小,甚至远比不上调整一下数据库的设置。在数据库一级通常是DBA的责任。一个优秀的DBA的职责,除了保障数据库安全稳定的运行,作好数据库的备份工作外,还要最大限度地利用现有资源,使资源达到最优配置而是系统的性能最佳化。同样,有大量的惨痛的教训告诉我们:一个应用设计不良的系统,无论多么优秀的DBA,他依然无能为力。最后迫使我们回到痛苦的现实中来:部分甚至全面地修改应用设计!
在这里我们谈的应用设计是广义的,包括数据库的结构的设计和应用程序的设计。对于我们开发人员来说,对于数据库结构,我们往往是无能为力的。通常我们会感慨,一个不良的数据库结构设计,再优秀的程序员也设计不出优秀的系统。但是,反过来也可以说,再优秀的数据库结构设计,不良的应用程序设计一样使得系统很糟糕
良好数据库结构设计+高性能硬件+优秀DBA+不良应用程序设计 = 垃圾!
硬件和DBA的问题,通常可以比较容易的得到解决,但是数据库结构设计和应用程序设计的问题,就是伤筋动骨的问题了。这往往意味着你的几个月甚至更长时间的辛苦一下子成为了无用的工作。作为应用程序的开发人员,我们必须清楚怎样开发一个良好的应用系统。通常我们的关注的焦点可能落在程序的功能的实现上,关于SQL,那简直是不需过问的事情。第四代高级语言么,只要我们告诉它我们需要什么,而无需关心它怎么去做。事实是这样的么?这是一个在大多数不成熟开发公司所面临的问题。如果你所开发的系统本身对性能没什么要求,ok,咱们在这里谈性能就没有什么意义。再谈SQL执行计划对于您来说是浪费时间,当然对于我也是。
如果您的系统对性能有要求,或者您愿意花一些时间来了解这方面的内容,那好,我们将开始讨论在应用程序设计中,我们开发人员应该重视的一个问题,那就是关于SQL的性能,更确切地说,是关于SQL的执行计划。
l 什么是执行计划
在讨论SQL执行计划之前,我们得先了解什么是执行计划。顾名思义所谓执行计划,就是我们写的SQL实际上仅仅是描述了我们希望获取怎样的数据,但是为了获取这些数据,数据库得指定出一个获取的方案、执行的路径,怎样去获取我们所需要的数据的这个方案或者说计划,我们称为执行计划。参考我们现实世界来说,比如你从外地要去北京,那么去北京是你的目标,但是怎样去北京呢?你可以为之指定一个计划,你可以制定一个乘坐交通工具和路线的计划。当然在我们人来说,确定最优的计划好象很简单,但是,假如我们说让你设计一个程序来选择一个最优的计划,那恐怕是一件异常困难的任务。虽然坐飞机飞过去很简单,但是价格太高,未必是最优的计划。况且也许坐飞机前后还需要考虑汽车、公交车等等因素。SQL的执行计划来说,对于多个表、多个索引的SQL来说,同样具有高度的复杂性。
说了这么多,我们来看看到底SQL执行计划是什么样子的。为了观察执行计划,我们需要在数据库中生成一个表来临时存放一些信息,通常来说,我们可以运行oracle自带的这个文件: $ORACLE_HOME/RDBMS/ADMIN/utlxplan.sql 。运行之后,我们来观察一个最简单的执行计划:
SQL> set autotrace traceonly
SQL> select count(*) from t;
Execution Plan
----------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'T'
这个查询采用FULL TABLE SCAN 方式来获得数据,表示对整个表的所有数据做一次全部扫描。那我们创建一个索引来观察一下
SQL> create index t_index on t(object_id);
Index created.
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select count(*) from t;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=9 Card=1)
1 0 SORT (AGGREGATE)
2 1 INDEX (FAST FULL SCAN) OF 'T_INDEX' (NON-UNIQUE) (Cost=9
Card=25374)
在这里我们创建了一个索引t_index,然后分析了一下表,我们再执行相同的查询,结果发现执行计划变化成了 INDEX (FAST FULL SCAN)。这表示不再对整个表进行数据的获取,而是通过全部扫描索引的数据来确定记录条数,由于这是一个非空的字段,所以这样做是合理的。我们知道索引主要存储了 key value 和 rowid,加一些结构等额外的开销,如果表的行长度很大的话,可能使用索引的IO远小于对整个表的扫描。这样不同的执行计划就带来性能的变化。
我们再看一个最基本的表连接的执行计划
SQL> select count(*) from t a,t_small b where a.object_id = b.object_id;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 NESTED LOOPS
3 2 TABLE ACCESS (FULL) OF 'T_SMALL'
4 2 INDEX (RANGE SCAN) OF 'T_INDEX' (NON-UNIQUE)
我们尝试交换一下 from 后面两个表的位置
SQL> select count(*) from t_small b ,t a where a.object_id = b.object_id;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 NESTED LOOPS
3 2 TABLE ACCESS (FULL) OF 'T'
4 2 INDEX (RANGE SCAN) OF 'T_SMALL_INDEX' (NON-UNIQUE)
通过对比上面两个执行计划我们可以看出,实际上由于from后面表的位置的顺序的改变,已经导致了执行计划的变化,两个例子相同点都是对于表连接使用了NESTED LOOPS 。但在第一个例子中是对表 t_small 进行全表扫描,而表t则是通过索引进行读取数据的。但在第二个例子中是对表t 进行全表扫描,而对t_small表通过索引获取数据。这个变化会不会造成性能的巨大变化?答案是肯定的,有可能不是一个数量级的变化。
在这里简单对NESTED LOOPS 进行一下解释,假定存在A、B两表,做表连接,以A表为基准,先取A的一条记录,然后去B表找和A能连接匹配的记录;然后顺序取A的下一条记录,再去B表中找连接匹配的记录,这样循环下去。我们设想在这样的情况下,如果表A比较小,而表B很大,并且两个表连接字段都存在索引,那以A表为基准去B表里面搜寻匹配记录是很快的,而若以B表为基准,虽然去A表里面搜寻记录也很快,但是由于 A<<B,则这样搜寻的次数大大增加。最后形成处理的时间可能有数量级的差异。
SQL> set serverout on
SQL> declare
2 n_time0 number;
3 n_time1 number;
4 n_time2 number;
5 n_count number;
6 begin
7 n_time0 := dbms_utility.get_time; //get the system time (1/100 seconds)
8
9 select count(*)
10 into n_count
11 from t a,t_small b
12 where a.object_id = b.object_id;
13
14 n_time1 := dbms_utility.get_time; //get the system time (1/100 seconds)
15
16 select count(*)
17 into n_count
18 from t_small a,t b
19 where a.object_id = b.object_id;
20
21 n_time2 := dbms_utility.get_time; //get the system time (1/100 seconds)
22
23 dbms_output.put_line('the first time: '||to_char(n_time1 - n_time0) );
24 dbms_output.put_line('the second time: '||to_char(n_time2 - n_time1) );
25 end;
26 /
the first time: 0
the second time: 10
PL/SQL procedure successfully completed.
在这里我们可以看出第一个查询使用了不到0.01 秒的时间,而第二个例子使用了0.1秒的时间,这已经是数量级的时间差异了。实际上,对于表连接,常见的还有另外两种方式,那就是SORT MERGE 和 HASH JOIN 。比如我们可以提示数据库使用HASH JOIN
SQL> select /*+use_hash(a,b)*/ count(*) from t a,t_small b where a.object_id = b.object_id;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=16 Card=1 Bytes=26)
1 0 SORT (AGGREGATE)
2 1 HASH JOIN (Cost=16 Card=23442 Bytes=609492)
3 2 TABLE ACCESS (FULL) OF 'T_SMALL' (Cost=1 Card=82 Bytes
=1066)
4 2 INDEX (FAST FULL SCAN) OF 'T_INDEX' (NON-UNIQUE) (Cost
=4 Card=28588 Bytes=371644)
在这里数据库采用了HASH JOIN的连接方式,我们可以再对比一下不同执行计划消耗的时间
SQL> declare
2 n_time0 number;
3 n_time1 number;
4 n_time2 number;
5 n_time3 number;
6 n_count number;
7 begin
8 n_time0 := dbms_utility.get_time; //get the system time (1/100 seconds)
9
10 select count(*)
11 into n_count
12 from t a,t_small b
13 where a.object_id = b.object_id;
14
15 n_time1 := dbms_utility.get_time; //get the system time (1/100 seconds)
16
17 select count(*)
18 into n_count
19 from t_small a,t b
20 where a.object_id = b.object_id;
21
22 n_time2 := dbms_utility.get_time; //get the system time (1/100 seconds)
23
24 select /*+use_hash(a,b)*/ count(*)
25 into n_count
26 from t a,t_small b
27 where a.object_id = b.object_id;
28
29 n_time3 := dbms_utility.get_time; //get the system time (1/100 seconds)
30
31
32 dbms_output.put_line('the first time: '||to_char(n_time1 - n_time0) );
33 dbms_output.put_line('the second time: '||to_char(n_time2 - n_time1) );
34 dbms_output.put_line('use hash join: '||to_char(n_time3 - n_time2) );
35 end;
36 /
the first time: 0
the second time: 9
use hash join: 0
PL/SQL procedure successfully completed.
(注:关于不同的执行计划的解释,大家可以登陆http://tahiti.oracle.com,那里包含了oracle的各版本的文档,通过搜索功能通常能满足您的大部分需求)
l ORACLE怎样产生执行计划
明白了什么是执行计划,那oracle到底是怎么产生执行SQL的呢。首先我们要明白oracle内部处理SQL的流程:
1:接收client发送来的SQL,通过hash value在共享池中查找,若存在,则进入4
2:进行语法检查、语义检查、权限检查
3:在共享池中分配空间,根据数据字典信息产生执行计划
4:绑定变量值
5:执行
对于单个SQL来说,性能影响最大的部分就在执行计划的产生。在oracle8i和9i版本中,数据库同时支持RULE-BASE、COST-BASE(10i中将取消RULE-BASE)。在RULE-BASE中,执行计划的产生跟数据库的数据的变化无关,而COST-BASE可通过anlayze object 从而使得数据库根据对象的统计信息来生成执行计划。由于根据对象的统计信息来产生执行计划,使得oracle可以在不同的数据量和数据分布的状况下选择合适的执行计划(要基于COST-BASE就必须分析对象,可参考dbms_stats包)。
在这里我们来尝试演示一下同一句SQL在COST-BASE下执行计划的变化,以此来说明执行计划跟数据和查询返回的结果集相关。
SQL> analyze table t compute statistics;
Table analyzed.
SQL> set autotrace traceonly
SQL> select * from t where object_id <10;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=8 Card=7 Bytes=609)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=8 Card=7 Bytes=
609)
2 1 INDEX (RANGE SCAN) OF 'T_INDEX' (NON-UNIQUE) (Cost=2 Car
d=7)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
1402 bytes sent via SQL*Net to client
425 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
5 rows processed
SQL> select * from t where object_id <1000;
980 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=54 Card=963 Bytes=83
781)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=54 Card=963 Bytes=83781)
Statistics
----------------------------------------------------------
0 recursive calls
6 db block gets
412 consistent gets
0 physical reads
0 redo size
101108 bytes sent via SQL*Net to client
7640 bytes received via SQL*Net from client
67 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
980 rows processed
从上面的例子我们可以看出,当我们选取的数据范围从10变化到1000的时候,执行计划已经发生了变化。这是一个最简单的执行计划跟跟返回数据有关的例子。事实上,oracle的优化器在产生执行计划的时候,跟很多的因素相关(包括并行处理、系统的变化、参数的变化、数据增长、数据库版本升级、开发产品的配置变化、索引的变化、优化模式的转换等等)。优化器在生成执行计划之前,会对这些因素进行估计和计算,对同一个SQL可以生成大量的执行计划,计算这些执行计划的COST,然后选取最小COST的执行计划然后执行。通常我们可以使用DBMS_STATS包进行对象的统计信息的搜集,这是产生执行计划的最重要的依据。
在这里呢,我们不得不指出一个问题,那就是ORACLE不可能对SQL的所有执行计划进行评估,因为产生执行计划的代价不能太大。尤其是复杂的SQL,oracle必须在使用有限的资源和时间之内,快速的做出选择。这就决定了oracle的选择的范围并不是所有可能的执行计划,又由于优化器本身的限制,并不保证一定选择最优的执行计划。关于这个问题的解决办法,可参考stored outlines 内容,我也曾经介绍过这方面的内容。
l 通过工具选取执行计划和追踪执行计划变化
SQL的执行计划很多,但是如果我们要通过手工来达到对比执行计划的目的却并不是一件轻松的事,那需要丰富的经验和大量的重复劳动。值得庆幸的是我们可以通过工具来把我们给解放出来。下面通过使用LECCO DBEXPERT演示一个寻求最优执行计划的例子。
我们打开DB EXPERT 的菜单工具条TOOLS——SQL Editor,然后尝试优化下面这条SQL:
select count(*)
from t a
where a.object_id in (select object_id
from t_small)
进行执行计划的分析后我们得到了25种和源代码不同的执行计划,如下图
pic_1.gif
接下来我们对所有改写的SQL的执行计划都运行10次,看到底是哪个执行计划最快
PIC_2.gif
从这里我们可以看出alt22 是最快的执行计划,那我们找到这条来对比一下
PIC_3.gif
从这里我们可以看到SQL被改写了
select /*+ RULE */ count(*)
from t a
where a.object_id in (select object_id
from t_small
GROUP BY object_id)
执行计划在工具中也能看见,采用的是nested loops,因为这两个表一张有2万都条记录,一张只有10条记录并且都有索引,所以正好适合这种执行计划。当然事实上,我们也可以顺便看看其他的执行计划,看的多了,对各种执行计划也就了解了。
SQL的执行计划,往往有可能随着环境的变化而变化。同样的SQL,优化器在不同的环境下选择的执行计划可能是不一样的,而影响执行计划的因素又太复杂,包括数据的变化、数据库的移植和升级、数据库参数的变化、硬件环境的变化等等。通常我们难以人为的预测那些因素会导致哪些SQL的执行计划的变化,甚至连跟踪执行计划的变化也是一件很困难的任务。这种情况尤其发生在系统有大的变动的时候,我们往往并没有把握确保未来的数据库的性能一定得到提升。就算是硬件的升级,比如内存的加大和CPU数量的增加,有可能还导致系统性能的下降。当然,优化模式从RULE——>COST是比较常见的一种导致问题的原因 ,更常见的是对数据库对象和最新数据进行分析了之后,反而比分析之前性能状况更糟糕。作为DBA往往并不清楚数据库的每一条SQL,那么我们就需要一个工具来提供这种功能。DB EXPERT提供了对比两个时间点的执行计划的变化,这对我们诊断和预测数据库性能的变化以及时做出决策有重大重用。
下面我们来看看DB EXPERT具体是怎样来对比执行计划的变化的。首先我们可以通过Db EXPERT的TOOLS——>SQL Inspector搜集数据库内存中的SQL,当然,我们也可以通过SQL Scanner扫描数据库对象、扫描程序源代码或者二进制文件来或许应用中的SQL,当然更可以通过手工编辑加入我们所想要考察的SQL。下面的例子,我通过SQL Inspector获取了我的本地数据库内存中的35条SQL,然后保存到 Plan Version Tracker。我们用来跟踪的工具也就是TOOLS——Plan Version Tracker。
既然是要比较,那我们首先就要建立一个比较的基准,为着这35条SQL,先在工具中创建一个基准线,如下图
PIC_4.gif
创建了基准线之后,我们尝试对数据库用户下的对象进行分析,然后再看执行计划是否有改变(当然这个分析的过程可以是在DB EXPERT中完成)。
SQL> begin
2 DBMS_STATS.GATHER_SCHEMA_STATS (
3 ownname => user,
4 cascade => true);
5 end;
6 /
PL/SQL procedure successfully completed.
我们这个时候在DB EXPERT中创建第二个Snapshot 来和前面的基准(Master Snapshot)做比较,结果如下
PIC_5.gif
结果发现COST整体有下降,并且有执行计划发生改变。选中中间的SQL,在下面具体显示了执行计划的对比。事实上我们这里仅仅是简单的做了一个对数据的分析前后的对比,现实情况复杂的多,包括参数的改变、升级、优化模式的转变、移植等等,但对于工具来说,Plan Version Tracker只认为是在两个不同的时间点之间来比较变化,并不关心这段时间我们曾经做过什么。我们可以在测试环境中模拟真实状况,然后根据前后的对比来衡量数据库性能的变化并做出针对性的解决办法。
l 总结
我们从数据库的性能谈起,引入了执行计划的概念,然后简单介绍了一下什么是执行计划,并做了几个例子给大家演示,对SQL的处理和优化器做了个简单的介绍。最后用工具给大家示范怎么通过改写SQL而获取最优的执行计划和怎样追踪执行计划的变化。
再重述到前面的,执行计划就如同我们为了去北京而制定的路线。但我们要问,起点在哪里?不同的起点执行计划不一样,最终的效果也不一样。那么对于我们工具或者优化器来说,SQL本身决定了起点,工具或者优化器是在这个起点的基础上来决定最优的路径,虽然工具可以改变起点,并且可以花足够多的时间和资源来搜索最优路径从而取代优化器的不足,但是,工具毕竟不能等同于人。工具能很好的辅助我们的工作,让我们写出高宵的代码,但是绝对不是说我们可以不负责任地扔进一句SQL进去然后就很智能的出来一个我们所想的理想化的结果。就好比你决定了起点在四川某个偏僻的县城,工具可能帮你把起点迁移到重庆或者成都,但却不能移到上海。
只有在应用程序的设计中,优化了我们的代码,我们才能构建复杂的性能得到保障的系统。优化的工作从系统的设计的第一天就应该开始。
********************************************
| ORACLE执行计划的一些基本概念 | |||||||||||||
|
一.相关的概念 Rowid的概念:rowid是一个伪列,既然是伪列,那么这个列就不是用户定义,而是系统自己给加上的。对每个表都有一个rowid的伪列,但是表中并不物理存储ROWID列的值。不过你可以像使用其它列那样使用它,但是不能删除改列,也不能对该列的值进行修改、插入。一旦一行数据插入数据库,则rowid在该行的生命周期内是唯一的,即即使该行产生行迁移,行的rowid也不会改变。 Recursive SQL概念:有时为了执行用户发出的一个sql语句,Oracle必须执行一些额外的语句,我们将这些额外的语句称之为'recursive calls'或'recursive SQL statements'。如当一个DDL语句发出后,ORACLE总是隐含的发出一些recursive SQL语句,来修改数据字典信息,以便用户可以成功的执行该DDL语句。当需要的数据字典信息没有在共享内存中时,经常会发生Recursive calls,这些Recursive calls会将数据字典信息从硬盘读入内存中。用户不比关心这些recursive SQL语句的执行情况,在需要的时候,ORACLE会自动的在内部执行这些语句。当然DML语句与SELECT都可能引起recursive SQL。简单的说,我们可以将触发器视为recursive SQL。 Row Source(行源):用在查询中,由上一操作返回的符合条件的行的集合,即可以是表的全部行数据的集合;也可以是表的部分行数据的集合;也可以为对上2个row source进行连接操作(如join连接)后得到的行数据集合。 Predicate(谓词):一个查询中的WHERE限制条件 Driving Table(驱动表):该表又称为外层表(OUTER TABLE)。这个概念用于嵌套与HASH连接中。如果该row source返回较多的行数据,则对所有的后续操作有负面影响。注意此处虽然翻译为驱动表,但实际上翻译为驱动行源(driving row source)更为确切。一般说来,是应用查询的限制条件后,返回较少行源的表作为驱动表,所以如果一个大表在WHERE条件有有限制条件(如等值限制),则该大表作为驱动表也是合适的,所以并不是只有较小的表可以作为驱动表,正确说法应该为应用查询的限制条件后,返回较少行源的表作为驱动表。在执行计划中,应该为靠上的那个row source,后面会给出具体说明。在我们后面的描述中,一般将该表称为连接操作的row source 1。 Probed Table(被探查表):该表又称为内层表(INNER TABLE)。在我们从驱动表中得到具体一行的数据后,在该表中寻找符合连接条件的行。所以该表应当为大表(实际上应该为返回较大row source的表)且相应的列上应该有索引。在我们后面的描述中,一般将该表称为连接操作的row source 2。 组合索引(concatenated index):由多个列构成的索引,如create index idx_emp on emp(col1, col2, col3, ……),则我们称idx_emp索引为组合索引。在组合索引中有一个重要的概念:引导列(leading column),在上面的例子中,col1列为引导列。当我们进行查询时可以使用”where col1 = ? ”,也可以使用”where col1 = ? and col2 = ?”,这样的限制条件都会使用索引,但是”where col2 = ? ”查询就不会使用该索引。所以限制条件中包含先导列时,该限制条件才会使用该组合索引。 可选择性(selectivity):比较一下列中唯一键的数量和表中的行数,就可以判断该列的可选择性。如果该列的”唯一键的数量/表中的行数”的比值越接近1,则该列的可选择性越高,该列就越适合创建索引,同样索引的可选择性也越高。在可选择性高的列上进行查询时,返回的数据就较少,比较适合使用索引查询。 1) 全表扫描(Full Table Scans, FTS) 为实现全表扫描,Oracle读取表中所有的行,并检查每一行是否满足语句的WHERE限制条件一个多块读操作可以使一次I/O能读取多块数据块(db_block_multiblock_read_count参数设定),而不是只读取一个数据块,这极大的减少了I/O总次数,提高了系统的吞吐量,所以利用多块读的方法可以十分高效地实现全表扫描,而且只有在全表扫描的情况下才能使用多块读操作。在这种访问模式下,每个数据块只被读一次。
2) 通过ROWID的表存取(Table Access by ROWID或rowid lookup) 行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置,所以通过ROWID来存取数据可以快速定位到目标数据上,是Oracle存取单行数据的最快方法。 使用ROWID存取的方法:
3)索引扫描(Index Scan或index lookup) 我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),然后根据rowid直接从表中得到具体的数据,这种查找方式称为索引扫描或索引查找(index lookup)。一个rowid唯一的表示一行数据,该行对应的数据块是通过一次i/o得到的,在此情况下该次i/o只会读取一个数据库块。 在索引中,除了存储每个索引的值外,索引还存储具有此值的行对应的ROWID值。索引扫描可以由2步组成:(1) 扫描索引得到对应的rowid值。 (2) 通过找到的rowid从表中读出具体的数据。每步都是单独的一次I/O,但是对于索引,由于经常使用,绝大多数都已经CACHE到内存中,所以第1步的I/O经常是逻辑I/O,即数据可以从内存中得到。但是对于第2步来说,如果表比较大,则其数据不可能全在内存中,所以其I/O很有可能是物理I/O,这是一个机械操作,相对逻辑I/O来说,是极其费时间的。所以如果多大表进行索引扫描,取出的数据如果大于总量的5% -- 10%,使用索引扫描会效率下降很多。如下列所示:
但是如果查询的数据能全在索引中找到,就可以避免进行第2步操作,避免了不必要的I/O,此时即使通过索引扫描取出的数据比较多,效率还是很高的
进一步讲,如果sql语句中对索引列进行排序,因为索引已经预先排序好了,所以在执行计划中不需要再对索引列进行排序
从这个例子中可以看到:因为索引是已经排序了的,所以将按照索引的顺序查询出符合条件的行,因此避免了进一步排序操作。 根据索引的类型与where限制条件的不同,有4种类型的索引扫描: 通过唯一索引查找一个数值经常返回单个ROWID。如果存在UNIQUE 或PRIMARY KEY 约束(它保证了语句只存取单行)的话,Oracle经常实现唯一性扫描。 SQL> explain plan for 使用一个索引存取多行数据,在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如>、<、<>、>=、<=、between)
使用index rang scan的3种情况:
(a) 在唯一索引列上使用了range操作符(> < <> >= <= between) 与全表扫描对应,也有相应的全索引扫描。而且此时查询出的数据都必须从索引中可以直接得到。
(4) 索引快速扫描(index fast full scan) 扫描索引中的所有的数据块,与 index full scan很类似,但是一个显著的区别就是它不对查询出的数据进行排序,即数据不是以排序顺序被返回。在这种存取方法中,可以使用多块读功能,也可以使用并行读入,以便获得最大吞吐量与缩短执行时间。 索引快速扫描的例子: BE_IX索引是一个多列索引:
只选择多列索引的第2列:
#p#三.表之间的连接 Join是一种试图将两个表结合在一起的谓词,一次只能连接2个表,表连接也可以被称为表关联。在后面的叙述中,我们将会使用”row source”来代替”表”,因为使用row source更严谨一些,并且将参与连接的2个row source分别称为row source1和row source 2。Join过程的各个步骤经常是串行操作,即使相关的row source可以被并行访问,即可以并行的读取做join连接的两个row source的数据,但是在将表中符合限制条件的数据读入到内存形成row source后,join的其它步骤一般是串行的。有多种方法可以将2个表连接起来,当然每种方法都有自己的优缺点,每种连接类型只有在特定的条件下才会发挥出其最大优势。 row source(表)之间的连接顺序对于查询的效率有非常大的影响。通过首先存取特定的表,即将该表作为驱动表,这样可以先应用某些限制条件,从而得到一个较小的row source,使连接的效率较高,这也就是我们常说的要先执行限制条件的原因。一般是在将表读入内存时,应用where子句中对该表的限制条件。 在后面的介绍中,都已: 连接类型: 排序 - - 合并连接(Sort Merge Join, SMJ) 如果row source已经在连接关联列上被排序,则该连接操作就不需要再进行sort操作,这样可以大大提高这种连接操作的连接速度,因为排序是个极其费资源的操作,特别是对于较大的表。预先排序的row source包括已经被索引的列(如a.col3或b.col4上有索引)或row source已经在前面的步骤中被排序了。尽管合并两个row source的过程是串行的,但是可以并行访问这两个row source(如并行读入数据,并行排序). SMJ连接的例子:
排序是一个费时、费资源的操作,特别对于大表。基于这个原因,SMJ经常不是一个特别有效的连接方法,但是如果2个row source都已经预先排序,则这种连接方法的效率也是蛮高的。 嵌套循环(Nested Loops, NL) 内部连接过程: 在上面的连接过程中,我们称Row source1为驱动表或外部表。Row Source2被称为被探查表或内部表。 在NESTED LOOPS连接中,Oracle读取row source1中的每一行,然后在row sourc2中检查是否有匹配的行,所有被匹配的行都被放到结果集中,然后处理row source1中的下一行。这个过程一直继续,直到row source1中的所有行都被处理。这是从连接操作中可以得到第一个匹配行的最快的方法之一,这种类型的连接可以用在需要快速响应的语句中,以响应速度为主要目标。 如果driving row source(外部表)比较小,并且在inner row source(内部表)上有唯一索引,或有高选择性非唯一索引时,使用这种方法可以得到较好的效率。NESTED LOOPS有其它连接方法没有的的一个优点是:可以先返回已经连接的行,而不必等待所有的连接操作处理完才返回数据,这可以实现快速的响应时间。 如果不使用并行操作,最好的驱动表是那些应用了where 限制条件后,可以返回较少行数据的的表,所以大表也可能称为驱动表,关键看限制条件。对于并行查询,我们经常选择大表作为驱动表,因为大表可以充分利用并行功能。当然,有时对查询使用并行操作并不一定会比查询不使用并行操作效率高,因为最后可能每个表只有很少的行符合限制条件,而且还要看你的硬件配置是否可以支持并行(如是否有多个CPU,多个硬盘控制器),所以要具体问题具体对待。 NL连接的例子:
哈希连接(Hash Join, HJ) 这种连接是在oracle 7.3以后引入的,从理论上来说比NL与SMJ更高效,而且只用在CBO优化器中。 HASH连接的例子:
要使哈希连接有效,需要设置HASH_JOIN_ENABLED=TRUE,缺省情况下该参数为TRUE,另外,不要忘了还要设置hash_area_size参数,以使哈希连接高效运行,因为哈希连接会在该参数指定大小的内存中运行,过小的参数会使哈希连接的性能比其他连接方式还要低。 总结一下,在哪种情况下用哪种连接方法比较好: 排序 - - 合并连接(Sort Merge Join, SMJ): 嵌套循环(Nested Loops, NL): 哈希连接(Hash Join, HJ): 笛卡儿乘积(Cartesian Product) 当两个row source做连接,但是它们之间没有关联条件时,就会在两个row source中做笛卡儿乘积,这通常由编写代码疏漏造成(即程序员忘了写关联条件)。笛卡尔乘积是一个表的每一行依次与另一个表中的所有行匹配。在特殊情况下我们可以使用笛卡儿乘积,如在星形连接中,除此之外,我们要尽量使用笛卡儿乘积,否则,自己想结果是什么吧! 注意在下面的语句中,在2个表之间没有连接。
CARTESIAN关键字指出了在2个表之间做笛卡尔乘积。假如表emp有n行,dept表有m行,笛卡尔乘积的结果就是得到n * m行结果。 |
************************************************
ORACLE数据库被划分成称作为表空间的逻辑区域——形成ORACLE数据库的逻辑结构。一个ORACLE数据库能够有一个或多个表空间,而一个表空间则对应着一个或多个物理的数据库文件。表空间是ORACLE数据库恢复的最小单位,容纳着许多数据库实体,如表、视图、索引、聚簇、回退段和临时段等。
每个ORACLE数据库均有SYSTEM表空间,这是数据库创建时自动创建的。SYSTEM表空间必须总要保持联机,因为其包含着数据库运行所要求的基本信息(关于整个数据库的数据字典、联机求助机制、所有回退段、临时段和自举段、所有的用户数据库实体、其它ORACLE软件产品要求的表)。
一个小型应用的ORACLE数据库通常仅包括SYSTEM表空间,然而一个稍大型应用的ORACLE数据库采用多个表空间会对数据库的使用带来更大的方便。
作用
表空间的作用能帮助DBA用户完成以下工作:
1.决定数据库实体的空间分配;
2.设置数据库用户的空间份额;
3.控制数据库部分数据的可用性;
4.分布数据于不同的设备之间以改善性能;
5.备份和恢复数据。
用户创建其数据库实体时其必须于给定的表空间中具有相应的权力,所以对一个用户来
说,其要操纵一个ORACLE数据库中的数据,应该:
1.被授予关于一个或多个表空间中的RESOURCE特权;
2.被指定缺省表空间;
3.被分配指定表空间的存储空间使用份额;
4.被指定缺省临时段表空间。
维护
表空间的维护是由ORACLE数据库系统管理员DBA通过SQL*PLUS语句实现的,其中表空间
创建与修改中的文件名是不能带路径的,因此DBA必须在ORACLE/DBS目录中操作。
1.新表空间的创建
语法格式:CREATE TABLESPACE 表空间名
DATAFILE 文件标识符[,文件标识符]...
[DEFAULT STORAGE(存储配置参数)]
[ONLINE\OFFLINE];
其中:文件标识符=’文件名’[SIZE整数[K\M][REUSE]
2.修改表空间配置
语法格式:ALTER TABLESPCE 表空间名
(ADD DATAFILE 文件标识符[,文件标识符]...
\RENAME DATAFILE ’文件名’[,’文件名’]...
TO ’文件名’[,’文件名’]...
\DEFAULT STORAGE(存储配置参数)
\ONLINE\OFFLINE[NORMAL\IMMEDIATE]
\(BEGIN\END)BACKUP);
3.取消表空间
语法格式:DROP TABLESPACE表空间名[INCLUDING CONTENTS];
4.检查表空间使用情况
(1)检查当前用户空间分配情况
SELECT tablespace_name,SUM(extents),SUM(blocks),SUM(bytes)
FROM user_segments
GROUP BY tablespace_name
(2)a.检查各用户空间分配情况
SELECT owner,tablespace_;
(2)b.检查各用户空间分配情况
SELECT owner,tablespace_name,SUM(extents),SUM(blocks),SUM(bytes)
FROM dba_segments
GROUP BY owner,tablespace_name;
(3) 检查当前用户数据库实体空间使用情况
SELECT tablespace_name,segment_name,segment_type,
COUNT(extent_id),SUM(blocks),SUM(bytes)
FROM user_extents
GROUP BY tablespace_name,segment_name,segment_type;
(4)检查各用户空间使用情况
SELECT owner,tablespace_name,COUNT(extent_id),SUM(blocks),
SUM(bytes) FROM user_extents
GROUP BY owner,tablespace_name;
(5)检查数据库空间使用情况
SELECT tablespace_name,COUNT(extent_id),SUM(blocks),SUM(bytes)
FROM user_extents
GROUP BY tablespace_name;
(6)检查当前用户自由空间情况
SELECT tablespace_name,COUNT(block_id),SUM(blocks),SUM(bytes)
FROM user_free_space
GROUP BY tablespace_name;
(7)检查数据库自由空间情况
SELECT tablespace_name,COUNT(block_id),SUM(blocks),SUM(bytes)
FROM dba_free_space
GROUP BY tablespace_name;
四、结论
表空间是ORACLE数据库系统维护的主要对象,通过本文能详细了解它的基本概念与作用
,并掌握其日常维护知识,从而保证ORACLE数据库系统的正常运行。
from V$SESSION A LEFT JOIN V$SQL B ON A.SQL_ADDRESS=B.ADDRESS AND A.SQL_HASH_VALUE=B.HASH_VALUE order by b.cpu_time desc
*****************************************
Oracle经典问答一览
internal/oracle
sys/change_on_install
system/manager
scott/tiger
sysman/oem_temp
2. ORACLE9IAS WEB CACHE的初始默认用户和密码?
administrator/administrator
3. oracle 8.0.5怎么创建数据库?
用orainst。如果有motif界面,可以用orainst /m
4. oracle 8.1.7怎么创建数据库?
dbassist
5. oracle 9i 怎么创建数据库?
dbca
6. oracle中的裸设备指的是什么?
裸设备就是绕过文件系统直接访问的储存空间
7. oracle如何区分 64-bit/32bit 版本???
$ sqlplus '/ AS SYSDBA'
SQL*Plus: Release 9.0.1.0.0 - Production on Mon Jul 14 17:01:09 2003
(c) Copyright 2001 Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.0.1.0.0 - Production
With the Partitioning option
JServer Release 9.0.1.0.0 - Production
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.0.1.0.0 - Production
PL/SQL Release 9.0.1.0.0 - Production
CORE 9.0.1.0.0 Production
TNS for Solaris: Version 9.0.1.0.0 - Production
NLSRTL Version 9.0.1.0.0 - Production
SQL>
8. SVRMGR什么意思?
svrmgrl,Server Manager.
9i下没有,已经改为用SQLPLUS了
sqlplus /nolog
变为归档日志型的
9. 请问如何分辨某个用户是从哪台机器登陆ORACLE的?
SELECT machine , terminal FROM V$SESSION;
10. 用什么语句查询字段呢?
desc table_name 可以查询表的结构
select field_name,... from ... 可以查询字段的值
select * from all_tables where table_name like '%'
select * from all_tab_columns where table_name='??'
11. 怎样得到触发器、过程、函数的创建脚本?
desc user_source
user_triggers
12. 怎样计算一个表占用的空间的大小?
select owner,table_name,
NUM_ROWS,
BLOCKS*AAA/1024/1024 "Size M",
EMPTY_BLOCKS,
LAST_ANALYZED
from dba_tables
where table_name='XXX';
Here: AAA is the value of db_block_size ;
XXX is the table name you want to check
13. 如何查看最大会话数?
SELECT * FROM V$PARAMETER WHERE NAME LIKE 'proc%';
SQL>
SQL> show parameter processes
NAME TYPE VALUE
------------------------------------ ------- ------------------------------
aq_tm_processes integer 1
db_writer_processes integer 1
job_queue_processes integer 4
log_archive_max_processes integer 1
processes integer 200
这里为200个用户。
select * from v$license;
其中sessions_highwater纪录曾经到达的最大会话数
14. 如何查看系统被锁的事务时间?
select * from v$locked_object ;
15. 如何以archivelog的方式运行oracle。
init.ora
log_archive_start = true
RESTART DATABASE
16. 怎么获取有哪些用户在使用数据库
select username from v$session;
17. 数据表中的字段最大数是多少?
表或视图中的最大列数为 1000
18. 怎样查得数据库的SID ?
select name from v$database;
也可以直接查看 init.ora文件
19. 如何在Oracle服务器上通过SQLPLUS查看本机IP地址 ?
select sys_context('userenv','ip_address') from dual;
如果是登陆本机数据库,只能返回127.0.0.1,呵呵
20. unix 下怎么调整数据库的时间?
su -root
date -u 08010000
21. 在ORACLE TABLE中如何抓取MEMO类型字段为空的资料记录?
select remark from oms_flowrec where trim(' ' from remark) is not null ;
22. 如何用BBB表的资料去更新AAA表的资料(有关联的字段)
UPDATE AAA SET BNS_SNM=(SELECT BNS_SNM FROM BBB WHERE AAA.DPT_NO=BBB.DPT_NO) WHERE BBB.DPT_NO IS NOT NULL;
23. P4计算机安装方法
将SYMCJIT.DLL改为SYSMCJIT.OLD
24. 何查询SERVER是不是OPS?
SELECT * FROM V$OPTION;
如果PARALLEL SERVER=TRUE则有OPS能
25. 何查询每个用户的权限?
SELECT * FROM DBA_SYS_PRIVS;
26. 如何将表移动表空间?
ALTER TABLE TABLE_NAME MOVE TABLESPACE_NAME;
27. 如何将索引移动表空间?
ALTER INDEX INDEX_NAME REBUILD TABLESPACE TABLESPACE_NAME;
28. 在LINUX,UNIX下如何激活DBA STUDIO?
OEMAPP DBASTUDIO
29. 查询锁的状况的对象有?
V$LOCK, V$LOCKED_OBJECT, V$SESSION, V$SQLAREA, V$PROCESS ;
查询锁的表的方法:
SELECT S.SID SESSION_ID, S.USERNAME, DECODE(LMODE, 0, 'None', 1, 'Null', 2, 'Row-S (SS)', 3, 'Row-X (SX)', 4, 'Share', 5, 'S/Row-X (SSX)', 6,
'Exclusive', TO_CHAR(LMODE)) MODE_HELD, DECODE(REQUEST, 0, 'None', 1, 'Null', 2, 'Row-S (SS)', 3, 'Row-X (SX)', 4, 'Share', 5, 'S/Row-X (SSX)',
6, 'Exclusive', TO_CHAR(REQUEST)) MODE_REQUESTED, O.OWNER||'.'||O.OBJECT_NAME||' ('||O.OBJECT_TYPE||')', S.TYPE LOCK_TYPE, L.ID1 LOCK_ID1,
L.ID2 LOCK_ID2 FROM V$LOCK L, SYS.DBA_OBJECTS O, V$SESSION S WHERE L.SID = S.SID AND L.ID1 = O.OBJECT_ID ;
30. 如何解锁?
ALTER SYSTEM KILL SESSION ‘SID,SERIR#’;
31. SQLPLUS下如何修改编辑器?
DEFINE _EDITOR="<编辑器的完整路经>" -- 必须加上双引号
来定义新的编辑器,也可以把这个写在$ORACLE_HOME/sqlplus/admin/glogin.sql里面使它永久有效。
32. ORACLE产生随机函数是?
DBMS_RANDOM.RANDOM
33. LINUX下查询磁盘竞争状况命令?
Sar -d
33. LINUX下查询CPU竞争状况命令?
sar -r
34. 查询当前用户对象?
SELECT * FROM USER_OBJECTS;
SELECT * FROM DBA_SEGMENTS;
35. 如何获取错误信息?
SELECT * FROM USER_ERRORS;
36. 如何获取链接状况?
SELECT * FROM DBA_DB_LINKS;
37. 查看数据库字符状况?
SELECT * FROM NLS_DATABASE_PARAMETERS;
SELECT * FROM V$NLS_PARAMETERS;
38. 查询表空间信息?
SELECT * FROM DBA_DATA_FILES;
39. ORACLE的INTERAL用户要口令?
修改 SQLNET.ORA
SQLNET.AUTHENTICATION_SERVICES=(NTS)
40. 出现JAVA.EXE的解决办法?
一般是将ORACLEORAHOMEXIHTTPSERVER改成手工激活可以的
X是8或9
41. 如何给表、列加注释?
SQL>comment on table 表 is '表注释';
注释已创建。
SQL>comment on column 表.列 is '列注释';
注释已创建。
SQL> select * from user_tab_comments where comments is not null;
42. 如何查看各个表空间占用磁盘情况?
SQL> col tablespace format a20
SQL> select
b.file_id 文件ID号,
b.tablespace_name 表空间名,
b.bytes 字节数,
(b.bytes-sum(nvl(a.bytes,0))) 已使用,
sum(nvl(a.bytes,0)) 剩余空间,
sum(nvl(a.bytes,0))/(b.bytes)*100 剩余百分比
from dba_free_space a,dba_data_files b
where a.file_id=b.file_id
group by b.tablespace_name,b.file_id,b.bytes
order by b.file_id
43. 如把ORACLE设置为MTS或专用模式?
#dispatchers="(PROTOCOL=TCP) (SERVICE=SIDXDB)"
加上就是MTS,注释就是专用模式,SID是指你的实例名。
44. 如何才能得知系统当前的SCN号 ?
select max(ktuxescnw * power(2, 32) + ktuxescnb) from x$ktuxe;
45. 请问如何在ORACLE中取毫秒?
9i之前不支持,9i开始有timestamp.
9i可以用select systimestamp from dual;
大家在应用ORACLE的时候可能会遇到很多看起来不难的问题, 特别对新手来说, 今天我简单把它总结一下, 发布给大家, 希望对大家有帮助! 和大家一起探讨, 共
同进步!
对ORACLE高手来说是不用看的.
46. 如何在字符串里加回车?
select 'Welcome to visit'||chr(10)||'www.CSDN.NET' from dual ;
47. 中文是如何排序的?
Oracle9i之前,中文是按照二进制编码进行排序的。
在oracle9i中新增了按照拼音、部首、笔画排序功能。设置NLS_SORT值
SCHINESE_RADICAL_M 按照部首(第一顺序)、笔划(第二顺序)排序
SCHINESE_STROKE_M 按照笔划(第一顺序)、部首(第二顺序)排序
SCHINESE_PINYIN_M 按照拼音排序
48. Oracle8i中对象名可以用中文吗?
可以
49. 如何改变WIN中SQL*Plus启动选项?
SQL*PLUS自身的选项设置我们可以在$ORACLE_HOME/sqlplus/admin/glogin.sql中设置。
50. 怎样修改oracel数据库的默认日期?
alter session set nls_date_format='yyyymmddhh24miss';
OR
可以在init.ora中加上一行
nls_date_format='yyyymmddhh24miss'
51. 如何将小表放入keep池中?
alter table xxx storage(buffer_pool keep);
52. 如何检查是否安装了某个patch?
check that oraInventory
53. 如何使select语句使查询结果自动生成序号?
select rownum,COL from table;
54. 如何知道数据裤中某个表所在的tablespace?
select tablespace_name from user_tables where table_name='TEST';
select * from user_tables中有个字段TABLESPACE_NAME,(oracle);
select * from dba_segments where …;
55. 怎么可以快速做一个和原表一样的备份表?
create table new_table as (select * from old_table);
55. 怎么在sqlplus下修改procedure?
select line,trim(text) t from user_source where order by line;
56. 怎样解除PROCEDURE被意外锁定?
alter system kill session ,把那个session给杀掉,不过你要先查出她的session id
or
把该过程重新改个名字就可以了。
57. SQL Reference是个什么东西?
是一本sql的使用手册,包括语法、函数等等,oracle官方网站的文档中心有下载.
58. 如何查看数据库的状态?
unix下
ps -ef | grep ora
windows下
看服务是否起来
是否可以连上数据库
59. 请问如何修改一张表的主键?
alter table aaa
drop constraint aaa_key ;
alter table aaa
add constraint aaa_key primary key(a1,b1) ;
60. 改变数据文件的大小?
用 ALTER DATABASE .... DATAFILE .... ;
手工改变数据文件的大小,对于原来的 数据文件有没有损害。
61. 怎样查看ORACLE中有哪些程序在运行之中?
查看v$sessions表
62. 怎么可以看到数据库有多少个tablespace?
select * from dba_tablespaces;
63. 如何修改oracle数据库的用户连接数?
修改initSID.ora,将process加大,重启数据库.
64. 如何查出一条记录的最后更新时间?
可以用logminer 察看
65. 如何在PL/SQL中读写文件?
UTL_FILE包允许用户通过PL/SQL读写操作系统文件。
66. 怎样把“&”放入一条记录中?
insert into a values (translate ('at{&}t','at{}','at'));
67. EXP 如何加QUERY参数?
EXP USER/PASS FILE=A.DMP TABLES(BSEMPMS)
QUERY='"WHERE EMP_NO=\'S09394\'\" ﹔
68. 关于oracle8i支持简体和繁体的字符集问题?
ZHS16GBK可以支
69. Data Guard是什么软件?
就是Standby的换代产品
70. 如何创建SPFILE?
SQL> connect / as sysdba
SQL> select * from v$version;
SQL> create pfile from spfile;
SQL> CREATE SPFILE FROM PFILE='E:\ora9i\admin\eygle\pfile\init.ora';
文件已创建。
SQL> CREATE SPFILE='E:\ora9i\database\SPFILEEYGLE.ORA' FROM PFILE='E:\ora9i\admin\eygle\pfile\init.ora';
文件已创建。
71. 内核参数的应用?
shmmax
含义:这个设置并不决定究竟Oracle数据库或者操作系统使用多少物理内存,只决定了最多可以使用的内存数目。这个设置也不影响操作系统的内核资源。
设置方法:0.5*物理内存
例子:Set shmsys:shminfo_shmmax=10485760
shmmin
含义:共享内存的最小大小。
设置方法:一般都设置成为1。
例子:Set shmsys:shminfo_shmmin=1:
shmmni
含义:系统中共享内存段的最大个数。
例子:Set shmsys:shminfo_shmmni=100
shmseg
含义:每个用户进程可以使用的最多的共享内存段的数目。
例子:Set shmsys:shminfo_shmseg=20:
semmni
含义:系统中semaphore identifierer的最大个数。
设置方法:把这个变量的值设置为这个系统上的所有Oracle的实例的init.ora中的最大的那个processes的那个值加10。
例子:Set semsys:seminfo_semmni=100
semmns
含义:系统中emaphores的最大个数。
设置方法:这个值可以通过以下方式计算得到:各个Oracle实例的initSID.ora里边的processes的值的总和(除去最大的Processes参数)+最大的那个
Processes×2+10×Oracle实例的个数。
例子:Set semsys:seminfo_semmns=200
semmsl:
含义:一个set中semaphore的最大个数。
设置方法:设置成为10+所有Oracle实例的InitSID.ora中最大的Processes的值。
例子:Set semsys:seminfo_semmsl=-200
72. 怎样查看哪些用户拥有SYSDBA、SYSOPER权限?
SQL>conn sys/change_on_install
SQL>select * from V_$PWFILE_USERS;
73. 如何单独备份一个或多个表?
exp 用户/密码 tables=(表1,…,表2)
74. 如何单独备份一个或多个用户?
exp system/manager owner=(用户1,用户2,…,用户n) file=导出文件
75. 如何对CLOB字段进行全文检索?
SELECT * FROM A WHERE dbms_lob.instr(a.a,'K',1,1)>0;
76. 如何显示当前连接用户?
SHOW USER
77. 如何查看数据文件放置的路径 ?
col file_name format a50
SQL> select tablespace_name,file_id,bytes/1024/1024,file_name from dba_data_files order by file_id;
78. 如何查看现有回滚段及其状态 ?
SQL> col segment format a30
SQL> SELECT SEGMENT_NAME,OWNER,TABLESPACE_NAME,SEGMENT_ID,FILE_ID,STATUS FROM DBA_ROLLBACK_SEGS
79. 如何改变一个字段初始定义的Check范围?
SQL> alter table xxx drop constraint constraint_name;
之后再创建新约束:
SQL> alter table xxx add constraint constraint_name check();
80. Oracle常用系统文件有哪些?
通过以下视图显示这些文件信息:v$database,v$datafile,v$logfile v$controlfile v$parameter;
81. 内连接INNER JOIN?
Select a.* from bsempms a,bsdptms b where a.dpt_no=b.dpt_no;
82. 如何外连接?
Select a.* from bsempms a,bsdptms b where a.dpt_no=b.dpt_no(+);
Select a.* from bsempms a,bsdptms b wherea.dpt_no(+)=b.dpt_no;
83. 如何执行脚本SQL文件?
SQL>@$PATH/filename.sql;
84. 如何快速清空一个大表?
SQL>truncate table table_name;
85. 如何查有多少个数据库实例?
SQL>SELECT * FROM V$INSTANCE;
86. 如何查询数据库有多少表?
SQL>select * from all_tables;
87. 如何测试SQL语句执行所用的时间?
SQL>set timing on ;
SQL>select * from tablename;
大家在应用ORACLE的时候可能会遇到很多看起来不难的问题, 特别对新手来说, 今天我简单把它总结一下, 发布给大家, 希望对大家有帮助! 和大家一起探讨, 共
同进步!
对ORACLE高手来说是不用看的.
88. CHR()的反函数是?
ASCII()
SELECT CHAR(65) FROM DUAL;
SELECT ASCII('A') FROM DUAL;
89. 字符串的连接
SELECT CONCAT(COL1,COL2) FROM TABLE ;
SELECT COL1||COL2 FROM TABLE ;
90. 怎么把select出来的结果导到一个文本文件中?
SQL>SPOOL C:\ABCD.TXT;
SQL>select * from table;
SQL >spool off;
91. 怎样估算SQL执行的I/O数 ?
SQL>SET AUTOTRACE ON ;
SQL>SELECT * FROM TABLE;
OR
SQL>SELECT * FROM v$filestat ;
可以查看IO数
92. 如何在sqlplus下改变字段大小?
alter table table_name modify (field_name varchar2(100));
改大行,改小不行(除非都是空的)
93. 如何查询某天的数据?
select * from table_name where trunc(日期字段)=to_date('2003-05-02','yyyy-mm-dd');
94. sql 语句如何插入全年日期?
create table BSYEAR (d date);
insert into BSYEAR
select to_date('20030101','yyyymmdd')+rownum-1
from all_objects
where rownum <= to_char(to_date('20031231','yyyymmdd'),'ddd');
95. 如果修改表名?
alter table old_table_name rename to new_table_name;
96. 如何取得命令的返回状态值?
sqlcode=0
97. 如何知道用户拥有的权限?
SELECT * FROM dba_sys_privs ;
98. 从网上下载的ORACLE9I与市场上卖的标准版有什么区别?
从功能上说没有区别,只不过oracle公司有明文规定;从网站上下载的oracle产品不得用于 商业用途,否则侵权。
99. 怎样判断数据库是运行在归档模式下还是运行在非归档模式下?
进入dbastudio,历程--〉数据库---〉归档查看。
100. sql>startup pfile和ifile,spfiled有什么区别?
pfile就是Oracle传统的初始化参数文件,文本格式的。
ifile类似于c语言里的include,用于把另一个文件引入
spfile是9i里新增的并且是默认的参数文件,二进制格式
startup后应该只可接pfile
(
ID NUMBER,
NAME VARCHAR2(100 BYTE),
PID NUMBER DEFAULT 0
);
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('2','11','1');
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('3','20','0');
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('4','12','1');
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('5','121','2');
从Root往树末梢递归
select * from TBL_TEST
start with id=1
connect by prior id = pid
从末梢往树ROOT递归
select * from TBL_TEST
start with id=5
connect by prior pid = id
资料引用:http://www.knowsky.com/390130.html
引文来源 Oracle用Start with...Connect By子句递归查询_Oracle教程_www.knowsky.com
|
/* Formatted on 2008/06/02 15:37 (Formatter Plus v4.8.7) */
INSERT INTO t_work (f_recid, f_jobid, f_ruleid, f_jobtype, f_operid, f_opername, f_buftime, f_assigntime, f_downtime, f_worktimes, f_finishtime) SELECT SYS_GUID () AS f_recid, f_jobid, f_ruleid, f_jobtype, f_operid, f_opername, f_buftime, f_assigntime,f_downtime, DECODE (f_downtime, null,1, f_downtime + 1) as f_worktimes, TO_CHAR (SYSDATE, 'yyyy-MM-dd hh:mm:ss') AS finishtime FROM t_buffer WHERE f_jobid = '21' 说明将t_buffer中的一条记录添加到t_work表中。 其中b_buffer中没有的列有f_recid和t_finishtime; f_worktimes需要加1。 SYS_GUID () 的意思是生成一个32位的永不重复的字符串。 DECODE (f_downtime, null,1, f_downtime + 1) 的意思是如果f_downtime为空(null)得到的值为1,否则为f_downtime + 1。 TO_CHAR (SYSDATE, 'yyyy-MM-dd hh:mm:ss')为格式化时间格式。在表t_work中f_finishtime的数据类型为varchar2.
|
ORA-14551: cannot perform a DML operation inside a query
上一篇 / 下一篇 2008-06-19 01:26:56 / 不允许评论 / 个人分类:《Oracle数据库精讲与疑难解析》
〖环境(Environment)〗< xmlnamespace prefix ="o" />
OS:SOLARIS 9
DB:ORACLE< xmlnamespace prefix ="st1" />10G
〖现象(Symptom) 〗
Step01:创建函数f_stu。
SQL> create or replace function f_stu
2 return varchar2
3 is
4 username varchar2(20);
5 predicate varchar2(100);
6 begin
7 INSERT INTO student2 (ID,FIRST_NAME,LAST_NAME,MAJOR,CURRENT_CREDITS)
8 VALUES(001,'MARY','KING','history',0);
9 commit;
10 return 'ok';
11 end;
12 /
Function created
这个函数往表student2种插入数据。
Step02:在SELECT语句中调用函数f_stu。
SQL> select f_stu()from dual;
select f_stu()from dual
ORA-14551: cannot perform. a DML operation inside a query
ORA-06512: at "F_STU",line 7
〖原理(Cause) 〗
在SELECT语句中不能对表进行修改(insert,update,delete)。本例中,SELECT语句中的函数试图往表student2中插入数据。
〖方法(Action) 〗
要想在SELECT语句中对表进行修改,可以使用自治事务(Autonomous Transactions,AT)。自治事务(Autonomous Transactions)是由另外一个事务调用的,这个叫事务做主事务(Main Transaction,MT)。自治事务(Autonomous Transactions)的提交(commit)和回滚(rollback)并不影响主事务(MT)。
Step01:将创建函数f_stu()的SQL语句
由:
create or replace function f_stu
return varchar2
is
username varchar2(20);
predicate varchar2(100);
begin
INSERT INTO student2(ID,FIRST_NAME,LAST_NAME,MAJOR,CURRENT_CREDITS)
VALUES(001,'MARY','KING','history',0);
commit;
return 'ok';
end;
改成:
create or replace function f_stu
return varchar2
is
PRAGMA AUTONOMOUS_TRANSACTION;
username varchar2(20);
predicate varchar2(100);
begin
INSERT INTO student2(ID,FIRST_NAME,LAST_NAME,MAJOR,CURRENT_CREDITS)
VALUES(001,'MARY','KING','history',0);
commit;
return 'ok';
end;
加入了PRAGMA AUTONOMOUS_TRANSACTION,表示使用自治事务(Autonomous Transactions)。
Step02:再次在SELECT语句中使用函数。
SQL> select f_stu() from dual;
F_STU()
--------------------------------------------------------------------------------
ok
SELECT语句执行成功,同时也往表student2中插入了数据。
引文来源 ORA-14551: cannot perform a DML operation inside a query - zeroCool的个人空间 - ITPUB个人空间 - powered by X-Space
浙公网安备 33010602011771号