Oracle Parallel Execution(并行执行)

Posted on

Oracle Parallel Execution(并行执行)

您还未登录!|登录|注册|帮助

David Dai -- Focus on Oracle

The important thing in life is to have a great aim ,and the determination to attain it!

Oracle Parallel Execution(并行执行)

分类: Oracle Advanced Knowledge Oracle Performance 2010-09-01 02:20 14688人阅读 评论(7) 收藏 举报 paralleloraclesqlinserttableiterator

关于Oracle 的并行执行,Oracle 官方文档有详细的说明:

                            Using Parallel Execution

http://download.oracle.com/docs/cd/E11882_01/server.112/e10837/parallel.htm/#VLDBG010

This chapter covers tuning in a parallel execution environment and discusses the following topics:

· Introduction to Parallel Execution

· How Parallel Execution Works

· Types of Parallelism

· Initializing and Tuning Parameters for Parallel Execution

· Tuning General Parameters for Parallel Execution

· Monitoring Parallel Execution Performance

· Miscellaneous Parallel Execution Tuning Tips

一. 并行(Parallel)和OLAP系统

并行的实现机制是: 首先,Oracle 会创建一个进程用于协调并行服务进程之间的信息传递,这个协调进程将需要操作的数据集(比如表的数据块)分割成很多部分,称为并行处理单元,然后并行协调进程给每个并行进程分配一个数据单元。比如有四个并行服务进程,他们就会同时处理各自分配的单元,当一个并行服务进程处理完毕后,协调进程就会给它们分配另外的单元,如此反复,直到表上的数据都处理完毕,最后协调进程负责将每个小的集合合并为一个大集合作为最终的执行结果,返回给用户。

并行处理的机制实际上就是把一个要扫描的数据集分成很多小数据集,Oracle 会启动几个并行服务进程同时处理这些小数据集,最后将这些结果汇总,作为最终的处理结果返回给用户。

这种数据并行处理方式在OLAP系统中非常有用,OLAP系统的表通常来说都是非常大,如果系统的CPU比较多,让所有的CPU共同来处理这些数据,效果就会比串行执行要高的多。

然而对于OLTP系统,通常来讲,并行并不合适,原因是OLTP系统上几乎在所有的SQL操作中,数据访问路劲基本上以索引访问为主,并且返回结果集非常小,这样的SQL 操作的处理速度一般非常快,不需要启用并行。

二. 并行处理的机制

            当Oracle 数据库启动的时候,实例会根据初始化参数:

                            PARALLEL_MIN_SERVERS=n

            的值来预先分配n个并行服务进程,当一条SQL 被CBO判断为需要并行执行时发出SQL的会话进程变成并行协助进程,它按照并行执行度的值来分配进程服务器进程。



            首先协调进程会使用ORACLE 启动时根据参数: parallel_min_servers=n的值启动相应的并行服务进程,如果启动的并行服务器进程数不足以满足并行度要求的并行服务进程数,则并行协调进程将额外启动并行服务进程以提供更多的并行服务进程来满足执行的需求。 然后星星协调进程将要处理的对象划分成小数据片,分给并行服务进程处理;并行服务进程处理完毕后将结果发送给并行协调进程,然后由并行协调进程将处理结果汇总并发送给用户。



            刚才讲述的是一个并行处理的基本流程。 实际上,在一个并行执行的过程中,还存在着并行服务进程之间的通信问题。

            在一个并行服务进程需要做两件事情的时候,它会再启用一个进程来配和当前的进程完成一个工作,比如这样的一条SQL语句:

            Select /* from employees order by last_name;



            假设employees表中last_name 列上没有索引,并且并行度为4,此时并行协调进程会分配4个并行服务进程对表employees进行全表扫描操作,因为需要对结果集进行排序,所以并行协调进程会额外启用4个并行服务进程,用于处理4个进程传送过来的数据,这新启用的用户处理传递过来数据的进程称为父进程,用户传出数据(最初的4个并行服务进程)成为子进程,这样整个并行处理过程就启用了8个并行服务进程。 其中每个单独的并行服务进程的行为叫作并行的内部操作,而并行服务进程之间的数据交流叫做并行的交互操作。

            这也是有时我们发现并行服务进程数量是并行度的2倍,就是因为启动了并行服务父进程操作的缘故。

三. 读懂一个并行处理的执行计划

CREATE TABLE emp2 AS SELECT /* FROM employees;

ALTER TABLE emp2 PARALLEL 2;

EXPLAIN PLAN FOR

SELECT SUM(salary) FROM emp2 GROUP BY department_id;

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());


| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | TQ |IN-OUT| PQ Distrib |


| 0 | SELECT STATEMENT | | 107 | 2782 | 3 (34) | | | |

| 1 | PX COORDINATOR | | | | | | | |

| 2 | PX SEND QC (RANDOM) | :TQ10001 | 107 | 2782 | 3 (34) | Q1,01 | P->S | QC (RAND) |

| 3 | HASH GROUP BY | | 107 | 2782 | 3 (34) | Q1,01 | PCWP | |

| 4 | PX RECEIVE | | 107 | 2782 | 3 (34) | Q1,01 | PCWP | |

| 5 | PX SEND HASH | :TQ10000 | 107 | 2782 | 3 (34) | Q1,00 | P->P | HASH |

| 6 | HASH GROUP BY | | 107 | 2782 | 3 (34) | Q1,00 | PCWP | |

| 7 | PX BLOCK ITERATOR | | 107 | 2782 | 2 (0) | Q1,00 | PCWP | |

| 8 | TABLE ACCESS FULL| EMP2 | 107 | 2782 | 2 (0) | Q1,00 | PCWP | |


The table EMP2 is scanned in parallel by one set of slaves while the aggregation for the GROUP BY is done by the second set. The PX BLOCK ITERATOR row source represents the splitting up of the table EMP2 into pieces so as to divide the scan workload between the parallel scan slaves. The PX SEND and PX RECEIVE row sources represent the pipe that connects the two slave sets as rows flow up from the parallel scan, get repartitioned through the HASH table queue, and then read by and aggregated on the top slave set. The PX SEND QC row source represents the aggregated values being sent to the QC in random (RAND) order. The PX COORDINATOR row source represents the QC or Query Coordinator which controls and schedules the parallel plan appearing below it in the plan tree.

            上面这段文字是从Oracle 联机文档上荡下来的。

http://download.oracle.com/docs/cd/E11882_01/server.112/e10821/ex_plan.htm/#PFGRF94687

通过执行计划,我们来看一下它的执行步骤:

            (1)并行服务进程对EMP2表进行全表扫描。

            (2)并行服务进程以ITERATOR(迭代)方式访问数据块,也就是并行协调进程分给每个并行服务进程一个数据片,在这个数据片上,并行服务进程顺序地访问每个数据块(Iterator),所有的并行服务进程将扫描的数据块传给另一组并行服务进程(父进程)用于做Hash Group操作。

            (3)并行服务父进程对子进程传递过来的数据做Hash Group操作。

            (4)并行服务进程(子进程)将处理完的数据发送出去。

            (5)并行服务进程(父进程)接收到处理过的数据。

            (6)合并处理过的数据,按照随即的顺序发给并行协调进程(QC:Query Conordinator)。

            (7)并行协调进程将处理结果发给用户。

当使用了并行执行,SQL的执行计划中就会多出一列:in-out。 该列帮助我们理解数据流的执行方法。 它的一些值的含义如下:

Parallel to Serial(P->S): 表示一个并行操作发送数据给一个串行操作,通常是并行incheng将数据发送给并行调度进程。

Parallel to Parallel(P->P):表示一个并行操作向另一个并行操作发送数据,疆场是两个从属进程之间的数据交流。

Parallel Combined with parent(PCWP): 同一个从属进程执行的并行操作,同时父操作也是并行的。

Parallel Combined with Child(PCWC): 同一个从属进程执行的并行操作,子操作也是并行的。

Serial to Parallel(S->P): 一个串行操作发送数据给并行操作,如果select 部分是串行操作,就会出现这个情况。

四.并行执行等待事件

            在做并行执行方面的性能优化的时候,可能会遇到如下等待时间:

                            PX Deq Credit: send blkd

            这是一个有并行环境的数据库中,从statspack 或者AWR中经常可以看到的等待事件。 在Oracle 9i 里面, 这个等待时间被列入空闲等待。 关于等待时间参考:

            Oracle 常见的33个等待事件

            [http://blog.csdn.net/tianlesoftware/archive/2010/08/12/5807800.aspx](http://blog.csdn.net/tianlesoftware/archive/2010/08/12/5807800.aspx)

一般来说空闲等待可以忽略它,但是实际上空闲等待也是需要关注的,因为一个空闲的等待,它反映的是另外的资源已经超负荷运行了。 基于这个原因,在Oracle 10g里已经把PX Deq Credit: send blkd等待时间不在视为空闲等待,而是列入了Others 等待事件范围。

PX Deq Credit: send blkd 等待事件的意思是: 当并行服务进程向并行协调进程QC(也可能是上一层的并行服务进程)发送消息时,同一时间只有一个并行服务进程可以向上层进程发送消息,这时候如果有其他的并行服务进程也要发送消息,就只能等待了。 知道获得一个发送消息的信用信息(Credit),这时候会触发这个等待事件,这个等待事件的超时时间为2秒钟。

            如果我们启动了太多的并行进程,实际上系统资源(CPU)或者QC 无法即时处理并行服务发送的数据,那么等待将不可避免。 对于这种情况,我们就需要降低并行处理的并行度。



            当出现PX Deq Credit:send blkd等待的时间很长时,我们可以通过平均等待时间来判断等待事件是不是下层的并行服务进程空闲造成的。该等待事件的超时时间是2秒,如果平均等待时间也差不多是2秒,就说明是下层的并行进程“无事所做”,处于空闲状态。 如果和2秒的差距很大,就说明不是下层并行服务超时导致的空闲等待,而是并行服务之间的竞争导致的,因为这个平均等待事件非常短,说明并行服务进程在很短时间的等待之后就可以获取资源来处理数据。

所以对于非下层的并行进程造成的等待,解决的方法就是降低每个并行执行的并行度,比如对象(表,索引)上预设的并行度或者查询Hint 指定的并行度。

五. 并行执行的使用范围

Oracle的并行技术在下面的场景中可以使用:

(1) Parallel Query(并行查询)

(2) Parallel DDL(并行DDL操作,如建表,建索引等)

(3) Parallel DML(并行DML操作,如insert,update,delete等)

5.1 并行查询

            并行查询可以在查询语句,子查询语句中使用,但是不可以使用在一个远程引用的对象上(如DBLINK)。



            一个查询能够并行执行,需要满足一下条件:

(1) SQL语句中有Hint提示,比如Parallel 或者 Parallel_index.

(2) SQL语句中引用的对象被设置了并行属性。

(3) 多表关联中,至少有一个表执行全表扫描(Full table scan)或者跨分区的Index range SCAN。

如: select //+parallel(t 4) / from t;

5.2 并行DDL 操作

5.2.1 表操作的并行执行

            以下表操作可以使用并行执行:

CREATE TABLE … AS SELECT

   ALTER TABLE … move partition

   Alter table … split partition

   Alter table … coalesce partition

DDL操作,我们可以通过trace 文件来查看它的执行过程。

示例:

查看当前的trace 文件:

// Formatted on 2010/8/31 23:33:00 (QP5 v5.115.810.9015) //

SELECT u_dump.VALUE

     || '/'

     || db_name.VALUE

     || '_ora_'

     || v$process.spid

     || NVL2 (v$process.traceid, '_' || v$process.traceid, NULL)

     || '.trc'

        "Trace File"

FROM v$parameter u_dump

           CROSS JOIN

              v$parameter db_name

        CROSS JOIN

           v$process

     JOIN

        v$session

     ON v$process.addr = v$session.paddr

WHERE u_dump.name = 'user_dump_dest'

     AND db_name.name = 'db_name'

     AND v$session.audsid = SYS_CONTEXT ('userenv', 'sessionid');

Trace File


d:/app/administrator/diag/rdbms/orcl/orcl/trace/orcl_ora_5836.trc

d:/app/administrator/diag/rdbms/orcl/orcl/trace/orcl_ora_3048.trc

SQL> alter session set events '10046 trace name context forever,level 12';

会话已更改。

SQL> create table 怀宁 parallel 4 as select /* from dba_objects;

表已创建。

SQL> alter session set events '10046 trace name context off' ;

会话已更改。

这里用到了ORACLE的event 时间。 10046事件是用来跟踪SQL语句的。开启事件后,相关的信息会写道trace 文件中,这也是之前我们查看trace 文件名的原因。 关于event事件,参考我的blog:

            Oracle 跟踪事件 set event

            [http://blog.csdn.net/tianlesoftware/archive/2009/12/13/4977827.aspx](http://blog.csdn.net/tianlesoftware/archive/2009/12/13/4977827.aspx)

有了trace文件, 我们可以用tkprof 工具,来查看trace 文件的内容。 关于tkprof 工具介绍,参考blog:

            使用 Tkprof 分析 ORACLE 跟踪文件

            [http://blog.csdn.net/tianlesoftware/archive/2010/05/29/5632003.aspx](http://blog.csdn.net/tianlesoftware/archive/2010/05/29/5632003.aspx)

进入trace 目录,用tkprof命令生成txt 文件,然后查看txt 文件。

d:/app/Administrator/diag/rdbms/orcl/orcl/trace>tkprof orcl_ora_3048.trc 安庆.txt sys=no

TKPROF: Release 11.2.0.1.0 - Development on 星期二 8月 31 23:45:25 2010

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.

d:/app/Administrator/diag/rdbms/orcl/orcl/trace>

5.2.2 创建索引的并行执行

            创建索引时使用并行方式在系统资源充足的时候会使性能得到很大的提高,特别是在OLAP系统上对一些很大的表创建索引时更是如此。 以下的创建和更改索引的操作都可以使用并行:

            Create index

            Alter index … rebuild

            Alter index … rebuild partition

            Alter index … split partition

一个简单的语法:create index t_ind on t(id) parallel 4;

监控这个过程和5.2.1 中表一样,需要通过10046事件。 这里就不多说了。

有关减少创建时间方法,参考blog:

            如何加快建 index 索引 的时间

            [http://blog.csdn.net/tianlesoftware/archive/2010/07/11/5664019.aspx](http://blog.csdn.net/tianlesoftware/archive/2010/07/11/5664019.aspx)

总结:

使用并行方式,不论是创建表,修改表,创建索引,重建索引,他们的机制都是一样的,那就是Oracle 给每个并行服务进程分配一块空间,每个进程在自己的空间里处理数据,最后将处理完毕的数据汇总,完成SQL的操作。

5.3 并行DML 操作

            Oracle 可以对DML操作使用并行执行,但是有很多限制。 如果我们要让DML 操作使用并行执行,必须显示地在会话里执行如下命令:

            SQL> alter session enable parallel dml;

会话已更改。

            只有执行了这个操作,Oracle 才会对之后符合并行条件的DML操作并行执行,如果没有这个设定,即使SQL中指定了并行执行,Oracle也会忽略它。

5.3.1 delete,update和merge 操作

            Oracle 对Delete,update,merge的操作限制在,只有操作的对象是分区表示,Oracle 才会启动并行操作。原因在于,对于分区表,Oracle 会对每个分区启用一个并行服务进程同时进行数据处理,这对于非分区表来说是没有意义的。

5.3.2 Insert 的并行操作

            实际上只有对于insert into … select … 这样的SQL语句启用并行才有意义。 对于insert into .. values… 并行没有意义,因为这条语句本身就是一个单条记录的操作。



            Insert 并行常用的语法是:

                            Insert //*+parallel(t 2) /*/ into t select //*+parallel(t1 2) /*/ /* from t1;



            这条SQL 语句中,可以让两个操作insert 和select 分别使用并行,这两个并行是相互独立,互补干涉的,也可以单独使用其中的一个并行。

六. 并行执行的设定

6.1 并行相关的初始话参数

6.1.1 parallel_min_servers=n

            在初始化参数中设置了这个值,Oracle 在启动的时候就会预先启动N个并行服务进程,当SQL执行并行操作时,并行协调进程首先根据并行度的值,在当前已经启动的并行服务中条用n个并行服务进程,当并行度大于n时,Oracle将启动额外的并行服务进程以满足并行度要求的并行服务进程数量。

6.1.2 parallel_max_servers=n

            如果并行度的值大于parallel_min_servers或者当前可用的并行服务进程不能满足SQL的并行执行要求,Oracle将额外创建新的并行服务进程,当前实例总共启动的并行服务进程不能超过这个参数的设定值。

6.1.3 parallel_adaptive_multi_user=true|false

            Oracle 10g R2下,并行执行默认是启用的。 这个参数的默认值为true,它让Oracle根据SQL执行时系统的负载情况,动态地调整SQL的并行度,以取得最好的SQL    执行性能。

6.1.4 parallel_min_percent

            这个参数指定并行执行时,申请并行服务进程的最小值,它是一个百分比,比如我们设定这个值为50. 当一个SQL需要申请20个并行进程时,如果当前并行服务进程不足,按照这个参数的要求,这个SQL比如申请到20/*50%=10个并行服务进程,如果不能够申请到这个数量的并行服务,SQL 将报出一个ORA-12827的错误。

            当这个值设为Null时,表示所有的SQL在做并行执行时,至少要获得两个并行服务进程。

6.2 并行度的设定

            并行度可以通过以下三种方式来设定:

(1)使用Hint 指定并行度。

(2)使用alter session force parallel 设定并行度。

(3)使用SQL中引用的表或者索引上设定的并行度,原则上Oracle 使用这些对象中并行度最高的那个值作为当前执行的并行度。

示例:

            SQL>Select //*+parallel(t 4) /*/ count(/*) from t;

            SQL>Alter table t parallel 4;

            SQL>Alter session force parallel query parallel 4;

Oracle 默认并行度计算方式:

(1)Oracle 根据CPU的个数,RAC实例的个数以及参数parallel_threads_per_cpu的值,计算出一个并行度。

(2)对于并行访问分区操作,取需要访问的分区数为并行度。

并行度的优先级别从高到低:

            Hint->alter session force parallel->表,索引上的设定-> 系统参数

实际上,并行只有才系统资源比较充足的情况下,才会取得很好的性能,如果系统负担很重,不恰当的设置并行,反而会使性能大幅下降。

七. 直接加载

            在执行数据插入或者数据加载的时候,可以通过append hint的方式进行数据的直接加载。

在insert 的SQL中使用APPEND,如:

                            Insert //*+append /*/ into t select /* from t1;

还可以在SQL/*LOADER里面使用直接加载:

   Sqlldr userid=user/pwd control=load.ctl direct=true

Oracle 执行直接加载时,数据直接追加到数据段的最后,不需要花费时间在段中需找空间,数据不经过data buffer直接写到数据文件中,效率要比传统的加载方式高。

示例:

SQL> create table t as select /* from user_tables;

表已创建。

SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';

SEGMENT_NA EXTENT_ID BYTES


T 0 65536

T 1 65536

T 2 65536

T 3 65536

T 4 65536

这里我们创建了一张表,分配了5个extents。

SQL> delete from t;

已删除979行。

SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';

SEGMENT_NA EXTENT_ID BYTES


T 0 65536

T 1 65536

T 2 65536

T 3 65536

T 4 65536

这里删除了表里的数据,但是查询,依然占据5个extents。因为delete不会收缩表空间,不能降低高水位。

SQL> insert into t select /* from user_tables;

已创建980行。

SQL> commit;

提交完成。

SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';

SEGMENT_NA EXTENT_ID BYTES


T 0 65536

T 1 65536

T 2 65536

T 3 65536

T 4 65536

用传统方式插入,数据被分配到已有的空闲空间里。

SQL> delete from t;

已删除980行。

SQL> commit;

提交完成。

SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';

SEGMENT_NA EXTENT_ID BYTES


T 0 65536

T 1 65536

T 2 65536

T 3 65536

T 4 65536

删除数据,用append直接插入看一下。

SQL> insert //+append // into t select /* from user_tables;

已创建980行。

SQL> commit;

提交完成。

SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';

SEGMENT_NA EXTENT_ID BYTES


T 0 65536

T 1 65536

T 2 65536

T 3 65536

T 4 65536

T 5 65536

T 6 65536

T 7 65536

T 8 65536

T 9 65536

已选择10行。

从结果可以看出,直接加载方式时,虽然表中有很多空的数据块,Oracle 仍然会额外的分配4个extent用于直接加载数据。

            直接加载的数据放在表的高水位(High water Mark:hwm)以上,当直接加载完成后,Oracle 将表的高水位线移到新加入的数据之后,这样新的数据就可以被用户使用了。

Oracle 高水位(HWM)

http://blog.csdn.net/tianlesoftware/archive/2009/10/22/4707900.aspx

7.1 直接加载和REDO

            直接加载在logging模式下,与传统加载方式产生的redo 日志差别不大,因为当一个表有logging属性时,即使使用直接加载,所有改变的数据依然要产生redo,实际上是所有修改的数据块全部记录redo,以便于以后的恢复,这时候直接加载并没有太大的优势。



            直接加载最常见的是和nologging一起使用,这时候可以有效地减少redo 的生成量。 注意的是,在这种情况下,直接加载的数据块是不产生redo的,只有一些其他改变的数据产生一些redo,比如表空间分配需要修改字典表或者修改段头数据块,这些修改会产生少量的redo。



            实际上,对于nologging 方式的直接加载,undo 的数据量也产生的很少,因为直接加载的数据并不会在回滚段中记录,这些记录位于高水位之上,在事务提交之前,对于其他用户来说是不可见的,所以不需要产生undo,事务提交时,Oracle 将表的高水位线移到新的数据之后,如果事务回滚,只需要保持高水位线不动即可,就好像什么都没有发生一样。



            注意,由于在nologging模式下,redo 不记录数据修改的信息,所以直接加载完后,需要立即进行相关的备份操作,因为这些数据没有记录在归档日志中,一旦数据损坏,只能用备份来恢复,而不能使用归档恢复。

Logging模式下示例:

SQL> set autot trace stat;

SQL> insert //+append // into t select /* from user_tables;

已创建980行。

统计信息


    132  recursive calls

     87  db block gets

   8967  consistent gets

      0  physical reads

 286572  redo size

    911  bytes sent via SQL/*Net to client

   1017  bytes received via SQL/*Net from client

      4  SQL/*Net roundtrips to/from client

      2  sorts (memory)

      0  sorts (disk)

    980  rows processed

SQL> rollback;

回退已完成。

SQL> insert into t select /* from user_tables;

已创建980行。

统计信息


      0  recursive calls

    144  db block gets

   9027  consistent gets

      0  physical reads

 267448  redo size

    927  bytes sent via SQL/*Net to client

   1004  bytes received via SQL/*Net from client

      4  SQL/*Net roundtrips to/from client

      2  sorts (memory)

      0  sorts (disk)

    980  rows processed

Nologging模式下示例:

SQL> alter table t nologging;

表已更改。

SQL> insert into t select /* from user_tables;

已创建980行。

统计信息


    239  recursive calls

    132  db block gets

   9061  consistent gets

      0  physical reads

 262896  redo size

    927  bytes sent via SQL/*Net to client

   1004  bytes received via SQL/*Net from client

      4  SQL/*Net roundtrips to/from client

      7  sorts (memory)

      0  sorts (disk)

    980  rows processed

SQL> rollback;

回退已完成。

SQL> insert //+append // into t select /* from user_tables;

已创建980行。

统计信息


      8  recursive calls

     40  db block gets

   8938  consistent gets

      0  physical reads

    340  redo size  -- redo 减少很多

    911  bytes sent via SQL/*Net to client

   1017  bytes received via SQL/*Net from client

      4  SQL/*Net roundtrips to/from client

      2  sorts (memory)

      0  sorts (disk)

    980  rows processed

这部分内容也可参考Blog:

            Oracle DML NOLOGGING

http://blog.csdn.net/tianlesoftware/archive/2010/07/11/5701596.aspx

7.2 直接加载和索引

            如果直接加载的表上有索引,Oracle不会像加载数据的方式那样来处理索引的数据,但是它同样需要维护一个索引,这个成本很高,同时会生成很多的redo。

            所以当使用直接加载时,通常是针对一些数据量非常大的表。如果这些表存在索引,将会带来很大的性能影响,这时可以考虑先将索引disable或者drop掉,等加载数据后,之后在重新建立索引。

nologging示例:

SQL> insert //+append // into t select /* from user_tables;

已创建980行。

统计信息


      0  recursive calls

     40  db block gets

   8936  consistent gets

      0  physical reads

    384  redo size

    911  bytes sent via SQL/*Net to client

   1017  bytes received via SQL/*Net from client

      4  SQL/*Net roundtrips to/from client

      2  sorts (memory)

      0  sorts (disk)

    980  rows processed

SQL> rollback;

回退已完成。

SQL> create index t_ind on t(table_name);

索引已创建。

SQL> insert //+append // into t select /* from user_tables;

已创建980行。

统计信息


     40  recursive calls

    170  db block gets

   8955  consistent gets

      4  physical reads

 149424  redo size

    911  bytes sent via SQL/*Net to client

   1017  bytes received via SQL/*Net from client

      4  SQL/*Net roundtrips to/from client

      3  sorts (memory)

      0  sorts (disk)

    980  rows processed

SQL> rollback;

回退已完成。

SQL> insert into t select /* from user_tables;

已创建980行。

统计信息


      8  recursive calls

    828  db block gets

   9037  consistent gets

      0  physical reads

 382832  redo size

    927  bytes sent via SQL/*Net to client

   1005  bytes received via SQL/*Net from client

      4  SQL/*Net roundtrips to/from client

      2  sorts (memory)

      0  sorts (disk)

    980  rows processed

SQL> rollback;

回退已完成。

7.3 直接加载和并行

            直接加载可以和并行执行一同使用,这样可以并行地向表中插入数据。 如:

SQL>alter session enable parallel dml; -- 这里必须显示的申明

SQL>insert //+append parallel(t,2) // into t select /* from t1;

SQL>insert //+append // into t select /* from t1;

注:在对insert 使用并行时,Oracle自动使用直接加载的方式进行数据加载,所以在这种情况下append是可以省略的。

            当使用并行加载时,Oracle 会按照并行度启动相应数量的并行服务进程,像串行执行的直接加载的方式一样,每个并行服务进程都单独分配额外的空间用于加载数据,实际上Oracle 为每个并行服务进程分配了一个临时段,每个并行服务进程将数据首先加载到各自的临时段上,当所有的并行进程执行完毕后,将各自的数据块合并到一起,放到高水位之后,如果事务提交,则将高水位移到新加载的数据之后。

7.4 直接加载和SQL/*LOADER

            在SQL/*LOADER中也可以使用直接加载,它比传统方式效率更高,因为它绕开了SQL的解析和数据缓冲区,直接将数据加载到数据文件,这对OLAP或者数据仓库系统非常有用。

指定加载:

            Sqlldr userid=user/pwd control=control.ctl direct=true

指定并行和加载:

            Sqlldr userid=user/pwd control=control.ctl direct=true parallel=true

SQL/*LOADER直接加载对索引的影响:

(1)索引为非约束性,直接加载可以在加载完毕后维护索引的完整性。

(2)索引为约束性索引,比如主键,直接加载仍然会将数据加载入库,但是会将索引置为unusable.

如果使用SQL/*LOADER的并行直接加载选项,并且表上有索引,将导致加载失败,这是我们可以在sqlloader中指定skip_index_maintenance=true, 来允许加载完成,但是索引状态会变成unusable,需要手工rebuild.

关于SQL/*LOADER的更多内容,参考blog:

            Oracle SQL Loader

            [http://blog.csdn.net/tianlesoftware/archive/2009/10/16/4674063.aspx](http://blog.csdn.net/tianlesoftware/archive/2009/10/16/4674063.aspx)

整理自《让Oracle 跑的更快》


Blog: http://blog.csdn.net/tianlesoftware

网上资源: http://tianlesoftware.download.csdn.net

相关视频:http://blog.csdn.net/tianlesoftware/archive/2009/11/27/4886500.aspx

DBA1 群:62697716(满); DBA2 群:62697977(满)

DBA3 群:63306533; 聊天 群:40132017 分享到:

7楼 tiankui6658 2013-03-31 11:16发表 [回复] [引用] [举报]简直就是官方教材啊6楼 syzcch 2012-10-16 13:05发表 [回复] [引用] [举报]总结的很到位啊5楼 syzcch 2012-09-13 14:18发表 [回复] [引用] [举报]| 0 | SELECT STATEMENT | | 107 | 2782 | 3 (34) | | | | 1 | PX COORDINATOR | | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | 107 | 2782 | 3 (34) | Q1,01 | P->S | QC (RAND) | | 3 | HASH GROUP BY | | 107 | 2782 | 3 (34) | Q1,01 | PCWP | | 4 | PX RECEIVE | | 107 | 2782 | 3 (34) | Q1,01 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | 107 | 2782 | 3 (34) | Q1,00 | P->P | HASH | 6 | HASH GROUP BY | | 107 | 2782 | 3 (34) | Q1,00 | PCWP | | 7 | PX BLOCK ITERATOR | | 107 | 2782 | 2 (0) | Q1,00 | PCWP | | 8 | TABLE ACCESS FULL| EMP2 | 107 | 2782 | 2 (0) | Q1,00 | PCWP | 在这个例子中,我觉得是有两组并行服务进程,分别用Q1,00和Q1,01来标注的吧 比如paralle(degree 4) 说明Q1,00是4个进程在跑,而Q1,01也是4个,他们的关系类似于生产者和消费者,请问这样理解对吗? 谢谢!4楼 我个名叫麦兜_sco 2012-02-14 15:44发表 [回复] [引用] [举报]有空希望能把你的文章看完...3楼 aimingl 2011-09-21 09:55发表 [回复] [引用] [举报]牛人,顶一下;再学习。。。2楼 gaopengtttt 2011-07-20 11:56发表 [回复] [引用] [举报]bu cuo o1楼 fendou1314 2011-06-22 23:58发表 [回复] [引用] [举报][e01][e01][e01][e03] 太棒了@! 您还没有登录,请[登录][注册]

/* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场 TOP

个人资料

Dave

  • 访问:4265571次
  • 积分:49439分
  • 排名:第13名

  • 原创:1009篇

  • 转载:96篇
  • 译文:1篇
  • 评论:1481条

文章搜索

Dave's Links

文章存档

展开 国外技术链接

官网链接

最新评论

SP1022: 大哥,在主库执行startup pfile='/home/oracle/product/10.2.0...

暖爱_晨: @chen0032:如果细想这个世界什么东西跟我们有关,那就只有感激每天的生活

暖爱_晨: 被突然的非技术类文章吸引,便决定关注lz!一篇在旅途的文章,一段追梦的旅程,一份难以割舍的亲情,一个...

bule2011orange: 很详细,谢谢dave

houxp666: 文笔真不错,淡而美

Enward: 很好,很强大,学些了

Theven: @mn900809:哦?我还是下载完,不能打开。你那个要是能打开,给我发一份吧!邮箱:aolin.w...

mn900809: 我下载下来了 您现在有没? 需要给您发送一份么?

已经擦肩而过: 不错啊,但有的我的自启动怎么是这样的啊?UUID=f5c84165-6890-470f-b731-d...

zhanglu668: @liyoubaidu:swap就是交换的意思,这里都指的是交换分区。 阅读排行

公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告QQ客服 微博客服 论坛反馈 联系邮箱:webmaster@csdn.net 服务热线:400-600-2320京 ICP 证 070598 号北京创新乐知信息技术有限公司 版权所有世纪乐知(北京)网络技术有限公司 提供技术支持江苏乐知网络技术有限公司 提供商务支持Copyright © 1999-2012, CSDN.NET, All Rights Reserved GongshangLogo

Oracle Parallel用法 并行技术

Posted on

Oracle Parallel用法 并行技术

一、Parallel 1.用途 强行启用并行度来执行当前SQL。这个在Oracle 9i之后的版本可以使用,之前的版本现在没有环境进行测试。也就是说,加上这个说明,可以强行启用Oracle的多线程处理功能。举例的话,就像电脑装了多核的CPU,但大多情况下都不会完全多核同时启用(2核以上的比较明显),使用parallel说明,就会多核同时工作,来提高效率。 但本身启动这个功能,也是要消耗资源与性能的。所有,一般都会在返回记录数大于100万时使用,效果也会比较明显。 2.语法 //+parallel(table_short_name,cash_number)// 这个可以加到insert、delete、update、select的后面来使用(和rule的用法差不多,有机会再分享rule的用法) 开启parallel功能的语句是: alter session enable parallel dml; 这个语句是DML语句哦,如果在程序中用,用execute的方法打开。 3.实例说明 用ERP中的transaction来说明下吧。这个table记录了所有的transaction,而且每天数据量也算相对比较大的(根据企业自身业务量而定)。假设我们现在要查看对比去年一年当中每月的进、销情况,所以,一般都会写成: 复制内容到剪贴板程序代码 程序代码

select to_char(transaction_date,'yyyymm') txn_month, sum( decode( sign(transaction_quantity),1,transaction_quantity,0 ) ) in_qty, sum( decode( sign(transaction_quantity),-1,transaction_quantity,0 ) ) out_qty from mtl_material_transactions mmt where transaction_date >= add_months( to_date(
to_char(sysdate,'yyyy')||'0101','yyyymmdd'), -12) and transaction_date <= add_months( to_date( to_char(sysdate,'yyyy')||'1231','yyyymmdd'), -12) group by to_char(transaction_date,'yyyymm') 这个SQL执行起来,如果transaction_date上面有加index的话,效率还算过的去;但如果没有加index的话,估计就会半个小时内都执行不出来。这是就可以在select 后面加上parallel说明。例如: 复制内容到剪贴板程序代码 程序代码

select //+parallel(mmt,10)// to_char(transaction_date,'yyyymm') txn_month, ... 这样的话,会大大提高执行效率。如果要将检索出来的结果insert到另一个表tmp_count_tab的话,也可以写成: 复制内容到剪贴板程序代码 程序代码

insert //+parallel(t,10)// into tmp_count_tab ( txn_month, in_qty, out_qty ) select //+parallel(mmt,10)// to_char(transaction_date,'yyyymm') txn_month, ... 插入的机制和检索机制差不多,所以,在insert后面加parallel也会加速的。关于insert机制,这里暂不说了。 Parallel后面的数字,越大,执行效率越高。不过,貌似跟server的配置还有oracle的配置有关,增大到一定值,效果就不明显了。所以,一般用8,10,12,16的比较常见。我试过用30,发现和16的效果一样。不过,数值越大,占用的资源也会相对增大的。如果是在一些package、function or procedure中写的话,还是不要写那么大,免得占用太多资源被DBA开K。 4.Parallel也可以用于多表 多表的话,就是在第一后面,加入其他的就可以了。具体写法如下: //+parallel(t,10) (b,10)// 5.小结 关于执行效率,建议还是多按照index的方法来提高效果。Oracle有自带的explan road的方法,在执行之前,先看下执行计划路线,对写好的SQL tuned之后再执行。实在没办法了,再用parallel方法。Parallel比较邪恶,对开发者而言,不是好东西,会养成不好习惯,导致很多bad SQL不会暴漏,SQL Tuning的能力得不到提升。我有见过某些人create table后,从不create index或primary key,认为写SQL时加parallel就可以了。

来源: [http://www.wudongqi.com/article/519.htm](http://www.wudongqi.com/article/519.htm)

oracle的Parallel 并行技术

启用Parallel**前的忠告:**只有在需要处理一个很大的任务,如需要几十分钟,几个小时的作业中,并且要有足够的系统资源的情况下(这些资源包括cpu,内存,io),您才应该考虑使用parallel。否则,在一个多并发用户下,系统本身资源负担已经很大的情况下,启用parallel,将会导致某一个会话试图占用了所有的资源,其他会话不得不去等待,从而导致系统系能反而下降的情况,一般情况下,oltp系统不要使用parallel,olap系统中可以考虑去使用。

Parallel分类

l 并行查询parallel query

l 并行dml parallel dml pdml

l 并行查询

并行查询允许将一个[sql]()select语句划分为多个较小的查询,每个部分的查询并发地运行,然后将各个部分的结果组合起来,提供最终的结果,多用于全表扫描,索引全扫描等,大表的扫描和连接、创建大的索引、分区索引扫描、大批量插入更新和删除 启用并行查询

告知[oracle](),对T1启用parallel查询,但并行度要参照系统的资源负载状况来确定。

利用hints提示,启用并行,同时也可以告知明确的并行度,否则oracle自行决定启用的并行度,这些提示只对该sql语句有效。

SQL> select //+ parallel(t1 8) // count(/*) from t1;

SQL> select degree from user_tableswheretable_name='T1';

DEGREE


DEFAULT

并行度为Default,其值由下面2个参数决定

SQL> show parameter cpu

NAME TYPE VALUE


cpu_count integer 2

parallel_threads_per_cpu integer 2

cpu_count表示cpu数

parallel_threads_per_cpu表示每个cpu允许的并行进程数

default情况下,并行数为cpu_count/*parallel_threads_per_cpu

取消并行设置

SQL> alter table t1 noparallel;

SQL> select degree from user_tables where table_name='T1';

DEGREE


    1

对于一个大的任务,一般的做法是利用一个进程,串行的执行,如果系统资源足够,可以采用parallel技术,把一个大的任务分成若干个小的任务,同时启用n个进程/线程,并行的处理这些小的任务,这些并发的进程称为并行执行服务器(parallel executeion[server]()),这些并发进程由一个称为并发协调进程的进程来管理

启用Parallel**前的忠告:**只有在需要处理一个很大的任务,如需要几十分钟,几个小时的作业中,并且要有足够的系统资源的情况下(这些资源包括cpu,内存,io),您才应该考虑使用parallel。否则,在一个多并发用户下,系统本身资源负担已经很大的情况下,启用parallel,将会导致某一个会话试图占用了所有的资源,其他会话不得不去等待,从而导致系统系能反而下降的情况,一般情况下,oltp系统不要使用parallel,oltp系统中可以考虑去使用。

Parallel分类

l 并行查询parallel query

l 并行dml parallel dml pdml

l 并行ddl parallel ddl pddl

l 并行查询

并行查询允许将一个sqlselect语句划分为多个较小的查询,每个部分的查询并发地运行,然后将各个部分的结果组合起来,提供最终的结果,多用于全表扫描,索引全扫描等,大表的扫描和连接、创建大的索引、分区索引扫描、大批量插入更新和删除

启用并行查询

SQL> ALTER TABLE T1 PARALLEL;

告知oracle,对T1启用parallel查询,但并行度要参照系统的资源负载状况来确定。

利用hints提示,启用并行,同时也可以告知明确的并行度,否则oracle自行决定启用的并行度,这些提示只对该sql语句有效。

SQL> select //+ parallel(t1 8) // count(/*) from t1;

SQL> select degree from user_tableswheretable_name='T1';

DEGREE


DEFAULT

并行度为Default,其值由下面2个参数决定

SQL> show parameter cpu

NAME TYPE VALUE


cpu_count integer 2

parallel_threads_per_cpu integer 2

cpu_count表示cpu数

parallel_threads_per_cpu表示每个cpu允许的并行进程数

default情况下,并行数为cpu_count/*parallel_threads_per_cpu

取消并行设置

SQL> alter table t1 noparallel;

SQL> select degree from user_tables where table_name='T1';

DEGREE


    1

数据字典视图

v$px_session

sid:各个并行会话的sid

qcsid:query coordinator sid,查询协调器sid

l 并行dml ** 并行dml包括insert,update,delete,merge,在pdml期间,oracle可以使用多个并行执行服务器来执行insert,update,delete,merge,多个会话同时执行,同时每个会话(并发进程)都有自己的undo段,都是独立的一个事务,这些事务要么由pdml协调器进程提交,要么都rollback。

在一个有充足I/o带宽的多cpu主机中,对于大规模的dml,速度可能会有很大的提升,尤其是在大型的数据仓库环境中。

并行dml需要显示的启用

SQL> alter session enable parallel dml;

Disable并行dml

SQL> alter session disable parallel dml; 来源: [http://space.itpub.net/8183550/viewspace-667633](http://space.itpub.net/8183550/viewspace-667633)

oracle并行查询一例

今天碰到一个开发人员反映SQL执行时间过长。根本无法得到结果集。 看到服务器压力也没有很高,估计又是一个非常消耗磁盘的查询。果然,发现是一个200w的表和一个超过1100w表的HASH JOIN . 简单的帮助优化了一个SQL后,SQL如下:

select count(ui.usin_uid_fk) from table1 av, table2 ui where av.av_usse_activatedate >= to_date('20090102', 'yyyymmdd') and av.av_usse_activatedate < to_date('20090401', 'yyyymmdd') and av.av_usse_uid_fk = ui.usin_uid_fk and ui.usin_mcnc_fk =XXX%'

   不难想象执行的不是很理想。近20分钟的执行时间,真是让人崩溃。

COUNT(UI.USIN_UID_FK)

                        1918591

Elapsed: 00:19:03.07

Statistics

                0    recursive calls
                0    db block gets
 32921639    consistent gets
     352073    physical reads
                0    redo size
            395    bytes sent via SQL/*Net to client
            503    bytes received via SQL/*Net from client
                2    SQL/*Net roundtrips to/from client
                0    sorts (memory)
                0    sorts (disk)
                1    rows processed

    对于那张TABLE2的大表(符合条件的超过1100w),决定试图通过并行来提高执行速度。SQL如下:

select //+parallel (tbl_userinfo 4)// count(ui.usin_uid_fk) from table1 av, table2 ui where av.av_usse_activatedate >= to_date('20090101', 'yyyymmdd') and av.av_usse_activatedate < to_date('20090401', 'yyyymmdd') and av.av_usse_uid_fk = ui.usin_uid_fk and ui.usin_mcnc_fk like 'XXX%';

  执行效果还是非常明显的。从19分钟多到1分45秒!其中consistent gets更是减少了一个数量级 -:)

COUNT(UI.USIN_UID_FK)

                        1918591

Elapsed: 00:01:45.15

Statistics

                0    recursive calls
                0    db block gets
    2571109    consistent gets
     124523    physical reads
                0    redo size
            395    bytes sent via SQL/*Net to client
            504    bytes received via SQL/*Net from client
                2    SQL/*Net roundtrips to/from client
                0    sorts (memory)
                0    sorts (disk)
                1    rows processed



  因为这个服务器为2×4核心的cpu,应该可以算是8个CPU,所以应该可以通过增加并行度来进一步减少执行时间。如下SQL:

SQL> select //+parallel (tbl_userinfo 8)// count(ui.usin_uid_fk) 2 from table1 av, table2 ui 3 where av.av_usse_activatedate >= to_date('20090101', 'yyyymmdd') 4 and av.av_usse_activatedate < to_date('20090401', 'yyyymmdd') 5 and av.av_usse_uid_fk = ui.usin_uid_fk 6 and ui.usin_mcnc_fk like '460%';

COUNT(UI.USIN_UID_FK)

                        1949033

Elapsed: 00:00:20.60

Statistics

                0    recursive calls
                0    db block gets
    2607524    consistent gets
        55050    physical reads
                0    redo size
            395    bytes sent via SQL/*Net to client
            503    bytes received via SQL/*Net from client
                2    SQL/*Net roundtrips to/from client
                0    sorts (memory)
                0    sorts (disk)
                1    rows processed

   可以说还是比较理想的。只有20S左右了。虽然最大并行度可以到CPU/*2,但是效果未必会好。进一步做一个16个并行度的SQL执行测试。

COUNT(UI.USIN_UID_FK)

                        1949033

Elapsed: 00:00:20.64

Statistics

                0    recursive calls
                0    db block gets
    2607524    consistent gets
        55299    physical reads
                0    redo size
            395    bytes sent via SQL/*Net to client
            504    bytes received via SQL/*Net from client
                2    SQL/*Net roundtrips to/from client
                0    sorts (memory)
                0    sorts (disk)
                1    rows processed


   没有任何提高,并且执行时间还稍高于并行度为8的SQL。
   通过以上测试我们不难发现:
   在处理大量数据查询,例如出现HASH JOIN的情况下,并行查询非常有效果的。也就是说并行查询在数据仓库这样的应用中会“大显身手”。
    但是并行查询的使用还是有很多限制的。例如相对较小的数据查询和连接是会适得其反的。盲目增加并行度也是大忌,相对来讲,并行度和CPU数相同比较好。这里的CPU数应该是指的核心数。例如服务器中有一个CPU是4核心的,并行度为4是好的。
    技术很难有十全十美的,最重要的是对于特定技术的使用要恰到好处,保证扬长避短。 -:)

以上测试环境: ORACLE 9.2.0.4 RHEL 4 U4

来源: [http://miracle.blog.51cto.com/255044/147058](http://miracle.blog.51cto.com/255044/147058) **

Oracle not in查不到应有的结果 (2)

Posted on

Oracle not in查不到应有的结果 (2)

Windows LiveWindows Live™

威's profileX-SpiritPhotosBlogListsMore

Blog

  • [

Entries ](http://x-spirit.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&_c=BlogPart)

  • [

Summary ](http://x-spirit.spaces.live.com/?_c11_BlogPart_BlogPart=summary&_c=BlogPart) Listed by: Date Category

Sorry, your entry can't be deleted right now. Please try again later.

January 25

Oracle not in查不到应有的结果

首先我要感谢aa和Liu Xing帮我发现了我日志中的错误。之前比较粗心,把3条SQL语句写成一样的了,对于给读者造成的麻烦,我深表抱歉。 今天我把原文做了修订,为了对得起读者对我的关注,我重新深入的研究了这个问题,在后面,我会把来龙去脉写清楚。 问题: 语句1:

Select / from table1 A where A.col1 not in ( select col1 from table2 B ) 如果这样,本来应该有一条数据,结果没有。 如果我改写成这样: 语句2: *

select / from table1 A where not exists (SELECT / FROM table2 B where B.col1 = A.col1) 结果就正确,有一条数据显示。 经过一番搜索,原以为是子查询结果集太大的原因。 后来有网上强人指点:子查询里面有空集。即子查询的结果集里面有NULL的结果。 把查询语句修改成:**语句3:

Select / from table1 A where A.col1 not in ( select col1 from table2 B where B.col1 is not null ) 果然就查出来了。而且一点不差。。。厉害阿~~~ 下面是针对本文题的分析: 1。 首先来说说Oracle中的NULL。 Oracle中的NULL代表的是无意义,或者没有值。将NULL和其他的值进行逻辑运算,运算过程中,NULL的表现更象是FALSE。 下面请看真值表: AND NULL OR NULL TRUE NULL TRUE FALSE FALSE NULL NULL NULL NULL 另外,NULL和其他的值进行比较或者算术运算(<、>、=、!=、+、-、/、/),结果仍是NULL。 如果想要判定某个值是否为NULL,可以用IS NULL或者IS NOT NULL。

  1. 再来说说Oracle中的IN。 in是一个成员条件, 对于给定的一个集合或者子查询,它会比较每一个成员值。 IN功能上相当于 =ANY 的操作,而NOT IN 功能上相当于 !=ALL 的操作。 IN在逻辑上实际上就是对给定的成员集合或者子查询结果集进行逐条的判定,例如: SELECT / FROM table1 A WHERE A.col1 in (20,50,NULL);实际上就是执行了 SELECT / FROM table1 A WHERE A.col1=20 OR A.col1=50 OR A.col1=NULL;这样,根据NULL的运算特点和真值表,我们可以看出,上边这个WHERE 字句可以被简化(如果返回NULL则无结果集返回,这一点和FALSE是一样的)为 WHERE A.col1=20 OR A.col1=50也就是说,如果你的table1中真的存在含有NULL值的col1列,则执行该语句,无法查询出那些值为null的记录。 再来看看NOT IN。根据逻辑运算关系,我们知道,NOT (X=Y OR N=M) 等价于 X!=Y AND N!=M,那么: SELECT / FROM table1 A WHERE A.col1 not in (20,50,NULL)等价于 SELECT / FROM table1 A WHERE A.col1!=20 AND A.col1!=50 AND A.col1!=NULL根据NULL的运算特性和真值表,该语句无论前两个判定条件是否为真,其结果一定是NULL或者FALSE。故绝对没有任何记录可以返回。 这就是为什么语句1查不到应有结果的原因。当然,如果你用NOT IN的时候,预先在子查询里把NULL去掉的话,那就没问题了,例如语句3。 有些童鞋可能要问了:那如果我想把A表里面那些和B表一样col1列的值一样的记录都查出来,即便A、B两表里面的col1列都包括值为NULL的记录的话,用这一条语句就没办法了吗? 我只能很遗憾的告诉你,如果你想在WHERE后面单纯用IN 似乎不太可能了,当然,你可以在外部的查询语句中将NULL条件并列进去,例如: SELECT /* FROM table1 A WHERE A.col1 in (SELECT B.col1 FROM table2 B) OR A.col1 IS NULL;
  2. 最后谈谈EXISTS。 有人说EXISTS的性能比IN要好。但这是很片面的。我们来看看EXISTS的执行过程: select / from t1 where exists ( select / from t2 where t2.col1 = t1.col1 )相当于: for x in ( select / from t1 ) loop if ( exists ( select / from t2 where t2.col1 = x.col1 ) then
      OUTPUT THE RECORD in x
    
    end if end loop 也就是说,EXISTS语句实际上是通过循环外部查询的结果集,来过滤出符合子查询标准的结果集。于是外部查询的结果集数量对该语句执行性能影响最大,故如果外部查询的结果集数量庞大,用EXISTS语句的性能也不一定就会好很多。 当然,有人说NOT IN是对外部查询和子查询都做了全表扫描,如果有索引的话,还用不上索引,但是NOT EXISTS是做连接查询,所以,如果连接查询的两列都做了索引,性能会有一定的提升。 当然至于实际的查询效率,我想还是具体情况具体分析吧。 那么我们不妨来分析一下语句2为什么能够的到正确的结果吧: 语句2是这样的:**

select / from table1 A where not exists (SELECT B.col1 FROM table2 B where B.col1 = A.col1) 实际上是这样的执行过程: for x in ( select / from table1 A ) loop if (not exists ( select / from table2 B where B.col1 = x.col1 ) then OUTPUT THE RECORD in x end if end loop 由于表A中不包含NULL的记录,所以,遍历完表A,也只能挑出表A中独有的记录。 这就是为什么语句2能够完成语句3的任务的原因。 但如果表A中存在NULL记录而表B中不存在呢? 这个问题请大家自己分析吧。哈哈。有答案了可以给我留言哦。 答案:A表中的NULL也会被查出来。因为select / from table2 B where B.col1 = NULL不返回结果,故 not exists ( select /* from table2 B where B.col1 = x.col1 )的值为真。 以上SQL运行结果在MySQL和Oracle上都已经通过。

11:33 AM | Blog it | 计算机与 Internet

Comments (1)

Please wait...

Sorry, the comment you entered is too long. Please shorten it. You didn't enter anything. Please try again.

Sorry, we can't add your comment right now. Please try again later. To add a comment, you need permission from your parent. Ask for permission

Your parent has turned off comments. Sorry, we can't delete your comment right now. Please try again later.

You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours. Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.

Complete the security check below to finish leaving your comment. The characters you type in the security check must match the characters in the picture or audio. To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in

Don't have a Windows Live ID? Sign up Picture of Xing Liu

Picture of Xing Liu Xing Liuwrote:

这几个命令行怎么都一样啊?

Feb. 11

Trackbacks

The trackback URL for this entry is:

http://x-spirit.spaces.live.com/blog/cns!CC0B04AE126337C0!844.trak Weblogs that reference this entry

SQL是否有用于字符串的聚合函数

Posted on

SQL是否有用于字符串的聚合函数 - Oracle 高级技术

您还未登录!|登录|注册|帮助

[关闭]

[关闭]

SQL Loader学习小记(命令行参考)

Posted on

SQL Loader学习小记(命令行参考)

SQL Loader 命令行参考 Command line Sample: SQLLDR CONTROL=sample.ctl, LOG=sample.log, BAD=baz.bad, DATA=etc.dat USERID=scott/tiger, ERRORS=999, LOAD=2000, DISCARD=toss.dsc, DISCARDMAX=5 常用的keywords: userid -- orACLE username/password control -- control file name log -- log file name bad -- bad file name data -- data file name discard -- discard file name discardmax -- number of discards to allow (Default all) skip -- number of logical records to skip (Default 0) load -- number of logical records to load (Default all) errors -- number of errors to allow (Default 50)(允许出错的记录数) rows -- number of rows in conventional path bind array or between direct path data saves (Default: Conventional path 64, Direct path all)(每次提交的记录数) bindsize -- size of conventional path bind array in bytes (Default 256000) silent -- suppress messages during run (header,feedback,errors,discards,partitions)(是否显示load信息) direct -- use direct path (Default FALSE) parfile -- parameter file: name of file that contains parameter specifications parallel -- do parallel load (Default FALSE) file -- file to allocate extents from skip_unusable_indexes -- disallow/allow unusable indexes or index partitions(Default FALSE) skip_index_maintenance -- do not maintain indexes, mark affected indexes as unusable (Default FALSE) commit_discontinued -- commit loaded rows when load is discontinued (Default FALSE) readsize -- size of read buffer (Default 1048576) external_table -- use external table for load; NOT_USED, GENERATE_ONLY, EXECUTE (Default NOT_USED) columnarrayrows -- number of rows for direct path column array (Default 5000) streamsize -- size of direct path stream buffer in bytes (Default 256000) multithreading -- use multithreading in direct path resumable -- enable or disable resumable for current session (Default FALSE) resumable_name -- text string to help identify resumable statement resumable_timeout -- wait time (in seconds) for RESUMABLE (Default 7200) date_cache -- size (in entries) of date conversion cache (Default 1000) 上述大部分的参数定义可以入在control file中的option里。 执行结果返回代码 All rows loaded successfully EX_SUCC All or some rows rejected EX_WARN All or some rows discarded EX_WARN Discontinued load EX_WARN Command-line or syntax errors EX_FAIL oracle errors nonrecoverable for SQL/*Loader EX_FAIL Operating system errors (such as file open/close and malloc) EX_FAIL For UNIX, the exit codes are as follows: EX_SUCC 0 EX_FAIL 1 EX_WARN 2 EX_FTL 3

来源: [http://www.wudongqi.com/article/540.htm](http://www.wudongqi.com/article/540.htm)