`
q272156430
  • 浏览: 275840 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

用Bulk Collect提高查询效率

阅读更多

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语句来实现批插入、删除和更新,这在大批量数据操作时可以显著提高执行效率。

do something like this:

   open cursor;
   loop
       fetch c bulk collect into l_c1, l_c2, ....... LIMIT 1000;
       for i in 1 .. l_c1.count
       loop
          your process....
       end loop;
       forall i in 1 .. l_c1.count
            insert into ..... values ( L_c1(i), .... );
       end loop;
       exit when c%notfound;
   end loop;

   close cursor

 

 

分享到:
评论

相关推荐

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

    使用 fetch bulk collect into 获取游标数据可以大大提高读取效率。例如,在我们的测试环境中,使用 fetch bulk collect into 获取 100000 条记录只需要 3.5 秒,而使用 fetch into 获取同样的记录则需要 15 秒以上...

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

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

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

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

    bulk collect学习

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

    bulk collect 使用实例

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

    记录 集合 BULK COLLECT FORALL 执行计划

    在PL/SQL编程环境中,集合操作BULK COLLECT和FORALL是提高数据库处理效率的关键特性。它们主要用于批量处理数据,减少数据库调用次数,从而优化性能。这些特性尤其适用于处理大量数据时,如循环遍历结果集并进行更新...

    oracle bulk collect

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

    sal,ename BULK COLLECT INTO

    当涉及到大量数据时,使用`BULK COLLECT INTO` 可以显著提高程序执行速度。这是因为: - 减少了网络传输的次数,因为数据是批量加载而非逐行加载。 - 减少了数据库服务器上的资源消耗,特别是在并发请求较多的情况...

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

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

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

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

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

    Oracle BULK COLLECT是Oracle数据库提供的一种高级PL/SQL特性,用于提高数据处理效率,尤其在处理大量数据时。在传统的PL/SQL编程中,我们通常使用循环来逐行处理查询结果,这种方式对于大数据集来说效率低下,因为...

    oracle 迅速查询和更新大数据

    2. **分区技术**:通过分区技术可以将大型表分割成更小的部分,这样在查询时只需要扫描相关的分区,而无需扫描整个表,从而提高查询效率。 3. **并行查询**:利用Oracle的并行查询功能可以让多个进程同时执行查询的...

    plsql编程之葵发宝典.txt

    BULK COLLECT不仅可以应用于简单的SELECT语句,还可以与游标结合使用,进一步提高程序的灵活性和效率。 ##### 1. FETCH BULK COLLECT INTO ```sql DECLARE CURSOR cur_ic01 IS SELECT * FROM ic01 WHERE ROWNUM ; ...

    Oracle 遍历游标的四种方式汇总(for、fetch、while、BULK COLLECT)

    - 在实际应用中,BULK COLLECT常用于减少数据库调用次数,提高大量数据处理的效率。 总结来说,Oracle遍历游标的方式有其各自的特点和适用场景。FOR循环简洁易用,适用于大多数情况;FETCH和WHILE循环提供了更精细...

    Oracle Bulk Binds技术分析.pdf

    批量绑定技术的核心在于减少PL/SQL和SQL引擎之间的上下文切换次数,从而提高效率。在传统的SQL语句执行过程中,每次SQL的执行都需要PL/SQL引擎和SQL引擎之间的切换,这会消耗一定的系统资源。而批量绑定则一次性处理...

    JAVA 与 Sql学习笔记

    对于SELECT语句,可以使用BULK COLLECT将查询结果集收集到一个集合中,进一步提高效率。例如: ```sql SELECT column1, column2 BULK COLLECT INTO collection_name FROM table_name; ``` 5. **LIMIT子句**:...

    High Performance PL/SQL from Steven Feuerstein

    使用NOCOPY hint可以避免这一过程,提高效率。 - **示例代码**: ```sql CREATE OR REPLACE FUNCTION get_employees RETURN EmpTab PIPELINED AS l_EmpTab EmpTab; BEGIN SELECT * BULK COLLECT INTO l_EmpTab...

Global site tag (gtag.js) - Google Analytics