暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 使用ROWTYPE更好,然后将75% 列值提取到不同的变量

askTom 2017-11-15
233

问题描述

嗨,汤姆,

我正在使用多个变量从表中获取列值 (显然,我正在使用INTO子句并获得具有过滤条件的一行)。

我也可以通过使用 % ROWTYPE来做到这一点。这样,它将获取所有列。

现在,问题是哪一个更快或占用更少的内存?哪个是最佳实践?

通过使用 % ROWTYPE将获取所有列,其中我可能不会在我的PLSQL代码块中使用很少的列值。仍然在获取这些价值。但是使用rowtype会保存多个变量的声明,这至少会保存LOC (这也不是问题)。

例如,

Employee表确实有10列,
ID,Emp_name,emp_code,性别,电子邮件,dep_id,雇主ID,组织代码,付款周期,地址

现在,在我的plsql代码块中,只需说我需要7列。我不需要dep_id,雇主 _id,组织 _code。

那么,我应该使用rowtype而不是创建7个不同的变量来存储这7个列值吗?

你能分享一下你对此的看法吗?

专家解答

获取更多列的明显区别是你会消耗更多的内存。

还有多少?嗯,不出所料,这取决于...

如果排除的列 (大部分) 为null,则差异很小:

create table t as 
  select level id,
         lpad('x', 20, 'x') c1,
         sysdate c2,
         sysdate c3,
         level c4,
         level c5,
         level c6,
         cast(null as varchar2(500)) c7,
         cast(null as varchar2(500)) c8,
         cast(null as varchar2(500)) c9
  from   dual
  connect by level <= 10000;
  
exec dbms_session.FREE_UNUSED_USER_MEMORY ;

declare
  type r_tab is table of t%rowtype index by binary_integer;
  all_cols r_tab;
  
begin

  select *
  bulk collect into all_cols
  from   t;
  
  show_mem('All cols, nulls');
    
end;
/

All cols, nulls session pga memory: 11.511

exec dbms_session.FREE_UNUSED_USER_MEMORY ;

declare
  type r is record (
    id t.id%type, c1 t.c1%type, c2 t.c2%type, 
    c3 t.c3%type, c4 t.c4%type, c5 t.c5%type, 
    c6 t.c6%type
  ); 
  type r_t is table of r index by binary_integer;
  sub_cols r_t;
  
begin
  
  select id, c1, c2, c3, c4, c5, c6
  bulk collect into sub_cols
  from   t;
  
  show_mem('Col subset, nulls');
  
end;
/

Col subset, nulls session pga memory: 10.761
复制


因此,选择所有列使用11.5mb,而排除那些为null的列则为10.7mb。不超过10,000行。

另一方面,如果您排除了包含长字符串的列,则节省的费用可能会很大:

drop table t purge;
create table t as 
  select level id,
         lpad('x', 20, 'x') c1,
         sysdate c2,
         sysdate c3,
         level c4,
         level c5,
         level c6,
         lpad('x', 500, 'x') c7,
         lpad('y', 500, 'y') c8,
         lpad('z', 500, 'z') c9
  from   dual
  connect by level <= 10000;
  
exec dbms_session.FREE_UNUSED_USER_MEMORY ;

declare
  type r_tab is table of t%rowtype index by binary_integer;
  all_cols r_tab;
  
begin

  select *
  bulk collect into all_cols
  from   t;
  
  show_mem('All cols, long strings');
    
end;
/

All cols, long strings session pga memory: 27.948

exec dbms_session.FREE_UNUSED_USER_MEMORY ;

declare
  type r is record (
    id t.id%type, c1 t.c1%type, c2 t.c2%type, 
    c3 t.c3%type, c4 t.c4%type, c5 t.c5%type, 
    c6 t.c6%type
  ); 
  type r_t is table of r index by binary_integer;
  sub_cols r_t;
  
begin
  
  select id, c1, c2, c3, c4, c5, c6
  bulk collect into sub_cols
  from   t;
  
  show_mem('Col subset, long strings');
  
end;
/

Col subset, long strings session pga memory: 10.761
复制


选择子集使用相同数量的内存 (10.7mb)。但是,现在获得所有列的数量已高达近28mb,增加了很多。这也可能会影响SQL本身的性能,特别是如果它是 “复杂的” 并且需要对数据进行排序或将其写入temp。

例如,在下面的SQL中,我使用了实现提示来强制写入temp。请注意,获取所有列的SQL使用更多的读取,写入和缓冲区:

set serveroutput off
alter session set statistics_level = all;
with rws as (
  select /*+ materialize */* from t
)
  select count(*) from rws;
  
select * 
from   table(dbms_xplan.display_cursor(null, null, 'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT                                                                                                                       
SQL_ID  cy1qpkps337c0, child number 1                                                                                                   
-------------------------------------                                                                                                   
with rws as (   select /*+ materialize */* from t )   select count(*)                                                                   
from rws                                                                                                                                
                                                                                                                                        
Plan hash value: 1481629063                                                                                                             
                                                                                                                                        
-------------------------------------------------------------------------------------------------------------------------------------   
| Id  | Operation                  | Name                       | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |   
-------------------------------------------------------------------------------------------------------------------------------------   
|   0 | SELECT STATEMENT           |                            |      1 |        |      1 |00:00:00.17 |    7560 |   5000 |   2500 |   
|   1 |  TEMP TABLE TRANSFORMATION |                            |      1 |        |      1 |00:00:00.17 |    7560 |   5000 |   2500 |   
|   2 |   LOAD AS SELECT           |                            |      1 |        |      0 |00:00:00.11 |    5047 |   2500 |   2500 |   
|   3 |    TABLE ACCESS FULL       | T                          |      1 |   8412 |  10000 |00:00:00.03 |    2506 |   2500 |      0 |   
|   4 |   SORT AGGREGATE           |                            |      1 |      1 |      1 |00:00:00.05 |    2507 |   2500 |      0 |   
|   5 |    VIEW                    |                            |      1 |   8412 |  10000 |00:00:00.04 |    2507 |   2500 |      0 |   
|   6 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D708F_3B7555B |      1 |   8412 |  10000 |00:00:00.03 |    2507 |   2500 |      0 |   
-------------------------------------------------------------------------------------------------------------------------------------   
                                                                                                                                        
Note                                                                                                                                    
-----                                                                                                                                   
   - dynamic statistics used: dynamic sampling (level=2) 
  
with rws as (
  select /*+ materialize */id, c1, c2, c3, c4, c5, c6 from t
)
  select count(*) from rws;
  
select * 
from   table(dbms_xplan.display_cursor(null, null, 'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT                                                                                                                       
SQL_ID  bzhjgyagqfq5a, child number 0                                                                                                   
-------------------------------------                                                                                                   
with rws as (   select /*+ materialize */id, c1, c2, c3, c4, c5, c6                                                                     
from t )   select count(*) from rws                                                                                                     
                                                                                                                                        
Plan hash value: 1481629063                                                                                                             
                                                                                                                                        
-------------------------------------------------------------------------------------------------------------------------------------   
| Id  | Operation                  | Name                       | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |   
-------------------------------------------------------------------------------------------------------------------------------------   
|   0 | SELECT STATEMENT           |                            |      1 |        |      1 |00:00:00.09 |    2682 |   2581 |     81 |   
|   1 |  TEMP TABLE TRANSFORMATION |                            |      1 |        |      1 |00:00:00.09 |    2682 |   2581 |     81 |   
|   2 |   LOAD AS SELECT           |                            |      1 |        |      0 |00:00:00.06 |    2590 |   2500 |     81 |   
|   3 |    TABLE ACCESS FULL       | T                          |      1 |   8412 |  10000 |00:00:00.03 |    2506 |   2500 |      0 |   
|   4 |   SORT AGGREGATE           |                            |      1 |      1 |      1 |00:00:00.03 |      86 |     81 |      0 |   
|   5 |    VIEW                    |                            |      1 |   8412 |  10000 |00:00:00.03 |      86 |     81 |      0 |   
|   6 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D7090_3B7555B |      1 |   8412 |  10000 |00:00:00.01 |      86 |     81 |      0 |   
-------------------------------------------------------------------------------------------------------------------------------------   
                                                                                                                                        
Note                                                                                                                                    
-----                                                                                                                                   
   - dynamic statistics used: dynamic sampling (level=2)   
复制


所以就我个人而言,我只会选择你需要的东西。但在许多情况下,这是调整的最后一英里。因此,除非你真的很紧张,或者有复杂的SQL来获取数据,否则我不会太担心它。通常在你的应用程序的其他地方会有更大的收益。

show_mem过程的代码:

create or replace procedure show_mem (
  details varchar2
) as
begin
  for mem in (
    select  vstt.name,
            max( vsst.value ) value
    from    v$sesstat vsst,
            v$statname vstt,
            v$session vses
    where   vstt.statistic# = vsst.statistic#
    and     vsst.sid = vses.sid
    and     vstt.name in (
      'session pga memory'
    )
    and     vses.username is not null
    and     vsst.sid = sys_context('USERENV', 'SID')
    group by vstt.name
    order by vstt.name
  ) loop
    dbms_output.put_line(
      details || ' ' || mem.name || ': ' || 
      round((mem.value/1024/1024), 3)
    );
  end loop;
end show_mem;
/
复制

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论