`
davidx
  • 浏览: 83090 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

使用Bulk Collect提高Oracle查询效率

阅读更多

http://www.cnblogs.com/rootq/archive/2008/11/17/1335491.html

 

Oracle8i中首次引入了Bulk Collect特性,该特性可以让我们在PL/SQL中能使用批查询,批查询在某些情况下能显著提高查询效率。现在,我们对该特性进行一些简单的测试和分析。

1. 首先,我们创建一个表,并插入100000条记录
在SQL/Plus中执行下列脚本:

drop table empl_tbl
/
create table empl_tbl(last_name varchar2(20),
first_name varchar2(10),
salary number(10))
/

begin
for i in 3000..102999 loop
insert into empl_tbl(last_name,first_name,salary) values('carl'||(i-3000),'wu'||(103000-i),i);
end loop;
end;
/
commit
/
select count(*) from empl_tbl;
/

2. 使用三种方法计算表中某一字段含有多少个不重复值

2.1 使用常规的Distinct来实现

SQL> select count(distinct last_name) "Distinct Last Name" from empl_tbl;

Distinct Last Name
------------------
            100000
 
Executed in 0.36 seconds

我们可以看到,常规方法需要0.36秒查出该表中有100000个不重复的Last_name值。

2.2 使用游标来实现

我们执行下面语句来统计Last_name字段的不重复值个数:

declare
  all_rows number(10);
  temp_last_name empl_tbl.last_name%type;
begin
  all_rows:=0;
  temp_last_name:=' ';
  for cur in (select last_name from empl_tbl order by last_name) loop
     
      if cur.last_name!=temp_last_name then
       all_rows:=all_rows+1;
      end if;
      temp_last_name:=cur.last_name;
     
  end loop;
  dbms_output.put_line('all_rows are '||all_rows);
end;

请注意上面代码中的黑体部分使用了一个For Loop游标,为了提高程序可读性,我们没有显示定义游标变量。

执行结果:
all_rows are 100000
PL/SQL procedure successfully completed
Executed in 1.402 seconds

游标需要1.4秒才能查出该表中有100000个不重复的Last_name值,所耗时间是Distinct查询的3倍多。

2.3 使用Bulk Collect批查询来实现

示例代码如下:
declare
  all_rows number(10);
  --首先,定义一个Index-by表数据类型
  type last_name_tab is table of empl_tbl.last_name%type index by binary_integer;
  last_name_arr last_name_tab;
  --定义一个Index-by表集合变量
  temp_last_name empl_tbl.last_name%type;
 
begin
  all_rows:=0;
  temp_last_name:=' ';
  --使用Bulk Collect批查询来充填集合变量
  select last_name bulk collect into last_name_arr from empl_tbl;
 
  for i in 1..last_name_arr.count loop
      if temp_last_name!=last_name_arr(i) then
       all_rows:=all_rows+1;
      end if;
      temp_last_name:=last_name_arr(i);
  end loop;
 dbms_output.put_line('all_rows are '||all_rows);
end;

请注意上面代码中,我们首先定义了一个Index-by表数据类型last_name_tab,然后定义了一个该集合数据类型的变量last_name_arr,最后我们使用Bulk Collect批查询来充填last_name_arr,请注意它的使用语法。

执行结果:
all_rows are 100000
PL/SQL procedure successfully completed
Executed in 0.28 seconds
从上面执行结果,我们可以看到,Bulk Collect批查询只需要0.28秒就能查出该表中有100000个不重复的Last_name值,所耗时间只有游标查询的1/5,同时它比Distinct常规查询的速度也要快。

3. 测试结果分析
为什么会出现上面的结果呢?我们可以使用Oracle的SQL_Trace来分析一下结果。在SQL命令行中,使用alter session set sql_trace=true语句打开Oracle的Trace,然后在命令行中执行上面三种查询并使用TKPROF工具生成Trace报告。

3.1 常规Distinct查询结果分析********************************************************************************

select count(distinct last_name)
from
 empl_tbl


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.28       0.32        198        425          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.28       0.32        198        425          4           1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 62 

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT GROUP BY
 100000   TABLE ACCESS FULL EMPL_TBL

 

********************************************************************************
上述查询首先对empl_tbl进行全表扫描,然后分组排序得出结果。SQL解析、执行的时间都可忽略不计,主要时间花在读取数据上,因为当前SQL只是一个查询,没有任何增、删改操作。在数据读取阶段,需要从磁盘读取198个Oracle数据块,一致性读取(query,consistent gets)数据块425块。因为磁盘物理读是非常耗时的,所以该查询执行起来不是特别快。

3.2 游标查询效率分析

 

********************************************************************************
SELECT LAST_NAME
FROM
 EMPL_TBL ORDER BY LAST_NAME


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch   100001      0.71       0.62        198        425          4      100000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total   100002      0.71       0.62        198        425          4      100000

Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 62     (recursive depth: 1)********************************************************************************该方法的主要耗时也是在数据读取阶段,虽然磁盘读取数据块和一致性读取数据块的数目同Distinct SQL查询相等,但是,因为该方法中的游标要循环100001次,所以上面的SQL的读取会发生100001次,总共读出了100000行数据,这就是为什么使用游标需要1.4秒的原因。下面我们看看使用Bulk Collect会发生什么?

3.3 Bulk Collect的查询效率分析

 

********************************************************************************


SELECT LAST_NAME
FROM
 EMPL_TBL


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.08       0.07          0        425          0      100000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.08       0.07          0        425          0      100000

Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 62     (recursive depth: 1)


********************************************************************************


虽然这种方法也要读取100000行数据,但是读取操作只发生了1次,并且Bulk Collect语句将所需数据一次性读入内存,所以该方法没有从磁盘读取数据块,所以这种方法比上述两种方法都具有优势,所以执行效率最高。

4. 结论
通过上面的测试和分析,我们可以看到Bulk Collect批查询在某种程度上可以提高查询效率,它首先将所需数据读入内存,然后再统计分析,这样就可以提高查询效率。但是,如果Oracle数据库的内存较小,Shared Pool Size不足以保存Bulk Collect批查询结果,那么该方法需要将Bulk Collect的集合结果保存在磁盘上,在这种情况下,Bulk Collect方法的效率反而不如其他两种方法,有兴趣的读者可以进一步测试。

另外,除了Bulk Collect批查询外,我们还可以使用FORALL语句来实现批插入、删除和更新,这在大批量数据操作时可以显著提高执行效率。

 

ps:简单记录下自己验证的结果

ps:按照例子跑了一遍,(我用的是9i)

      发现数据为10万条时,

          distinct 查询时间是:0.29 (多次查询后,时间会降低到0.05 seconds左右)

          游标查询时间是:0.27 (多次查询后,时间会升高到3.7 seconds左右)

          bulk collect 查询时间是:1.683

      数据为100万条时,

          distinct 查询时间是:9.083 seconds(多次查询后,时间会降低到5 seconds左右)

          游标查询时间是:2.945 seconds (多次查询后,时间会升高到3.2 seconds左右)

          bulk collect 查询时间是:18.506 seconds

分享到:
评论

相关推荐

    Oracle 中使用 fetch bulk collect into 批量效率的读取游标数据

    Oracle 中使用 fetch bulk collect into 批量效率的读取游标数据 Oracle 中的游标数据读取是数据库开发中非常常见的操作。通常,我们使用 fetch some_cursor into var1, var2 形式来获取游标数据,当游标中的记录数...

    使用BULK COLLECT, MERGE 语句提高sql执行效率

    详细介绍了使用 BULK COLLECT 进行批量操作 提高sql的执行效率 使用MERGE INTO USING 一条sql搞定 新增和修改 使用connect by 进行递归树查询

    oracle批量处理(bulk collect)

    - **SELECT INTO**:可以使用`BULK COLLECT`来一次性获取查询结果。 - **FETCH INTO**:结合游标使用`BULK COLLECT`一次性获取多行数据。 - **RETURNING INTO**:在`DELETE`或`UPDATE`语句后,使用`BULK COLLECT`来...

    Oracle批量查询、删除、更新使用BULK COLLECT提高效率

    Oracle数据库提供了一种高效的方法来处理批量操作,如查询、删除和更新,这...在进行批量查询、删除或更新时,使用BULK COLLECT不仅能提高程序的运行速度,还能降低资源消耗,是优化Oracle数据库应用程序的重要技巧。

    oracle bulk collect

    这段代码示例虽然较为杂乱,但可以提炼出的关键点主要包括:如何使用`BULK COLLECT`来提高查询效率、如何声明和使用表类型(如`TABLE OF`)以及如何在PL/SQL过程中实现数据的批量处理。 ### Oracle BULK COLLECT...

    bulk collect学习

    在 Oracle 数据库中,Bulk Collect 是一个非常重要的特性,它主要用在 PL/SQL 代码中,用于提高数据处理的效率。Bulk Collect 允许一次性地将查询结果集批量加载到一个集合(collections)中,而不是传统的逐行处理...

    bulk collect 使用实例

    结合一个存储过程的实例,介绍了 bulk collect 的使用

    oracle下巧用bulk collect实现cursor批量fetch的sql语句

    总之,Oracle的Bulk Collect是处理大数据集时的一个强大工具,它能够提高PL/SQL代码的执行效率,减少资源消耗。熟练掌握并适时应用Bulk Collect,对于优化数据库性能至关重要。通过实践和调整,你可以找到最适合你...

    sal,ename BULK COLLECT INTO

    ### "sal,ename BULK COLLECT INTO" 相关知识...总之,`BULK COLLECT INTO` 是Oracle PL/SQL中一项非常有用的功能,它能够显著提高数据处理的效率。在实际开发中,合理运用这一特性可以极大地提升应用程序的性能表现。

    oracle 迅速查询和更新大数据

    综上所述,通过使用批量处理技术、引用游标以及SQL性能优化技巧等方法,可以有效地提高Oracle数据库在处理大数据时的查询和更新性能。这些技术的应用不仅能够提高系统的响应速度,还能增强其稳定性和可靠性。

    Oracle BULK COLLECT批量取数据解决方法

    在Oracle数据库中,BULK COLLECT 还可以与其他操作结合使用,如BULK INSERT用于批量插入数据,或者与FORALL一起使用,进行批量更新或删除。这些技术通常在处理大数据量时,能显著提升应用程序的性能,并减少资源消耗...

    Oracle查询优化改写-技巧与案例

    书中的改写技巧可能涉及到如何将游标改写为集合操作,或者使用 bulk collect 和 for all 语句提高效率。 8. **存储过程和函数优化**:优化存储过程和函数,包括减少调用次数,使用绑定变量,以及避免在过程中进行大...

    浅谈PL/SQL批处理语句:BULK COLLECT与FORALL对优化做出的贡献

    BULK COLLECT 是一个用于加速查询的特性,它允许一次性地将查询结果集加载到集合(collections)中,而不是逐行处理。这样避免了频繁的上下文切换,减少了PL/SQL和SQL引擎之间的交互次数,从而提升了整体性能。以下...

    Oracle 查询优化,个人练习

    批量处理可以提高性能,例如使用BULK COLLECT和FORALL语句。 6. **绑定变量**:使用绑定变量可以提高重用执行计划的效率,避免因参数化不佳导致的硬解析。 7. **查询重写**:通过数据库的查询重写功能,可以将复杂...

    Oracle查询优化改写技巧与案例

    `,应改写为`SELECT * BULK COLLECT INTO collection FROM table;`,然后在PL/SQL集合中处理。 五、使用绑定变量 1. 绑定变量可以减少解析次数,提高执行效率。 2. 避免在SQL语句中硬编码值,使用?占位符代替。 ...

    oracle游标使用及实例

    `BULK COLLECT`允许一次性从游标中获取多行数据,并存储到集合中,这可以显著提高性能。 首先定义一个集合类型: ```sql TYPE type_name IS TABLE OF data_type; ``` 接着定义一个该类型的变量: ```sql ...

    Oracle 批查询

    bulk collect在 select ... into、fetch ... into、returning ... into中的应用。

Global site tag (gtag.js) - Google Analytics