微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

oracle – 为什么我不应该创建所有PL / SQL-only VARCHAR2 32767字节?

或者我应该?

(标题的灵感来自于Gary Myers在Why does Oracle varchar2 have a mandatory size as a definition parameter?年的评论)

考虑以下变量:

declare
  -- database table column interfacing variable
  v_a tablex.a%type; -- tablex.a is varchar2
  -- PL/sql only variable
  v_b varchar2(32767); -- is this a poor convention ?
begin
  select a into v_a from tablex where id = 1;
  v_b := 'Some arbitrary string: ' || v_a; -- ignore potential ORA-06502
  insert into tabley(id,a) values(1,v_a); -- tablex.a and tabley.a types match
  v_b := v_b || ' More arbitrary characters';
end;
/

变量v_a用于连接数据库表列,因此使用%type attribute.但是如果我知道数据类型是varchar2,为什么我不应该使用varchar2(4000)或varchar2(32767)来保证从数据库列读取的字符串将总是适合PL / sql变量?除了%type属性的优越性之外,还有其他任何反对这个约定的论据吗?

变量v_b仅用于PL / sql代码,通常返回到JDBC客户端(Java / Python程序,Oracle SOA / OSB等)或转储到平面文件(使用UTL_FILE).如果varchar2表示例如csv-line为什么我应该费心去计算确切的最大可能长度(除了验证该行在所有情况下都适合32767字节所以我不需要clob)并且每次我的数据模型改变时重新计算?

有很多问题涵盖了sql中的varchar2长度语义,并解释了为什么varchar2(4000)在sql中很糟糕.此外,sql和PL / sql varchar2-type之间的区别很好:

> What is the size limit for a varchar2 PL/SQL subprogram argument in Oracle?
> VARCHAR(MAX) versus VARCHAR(n) in Oracle
> Why does Oracle varchar2 have a mandatory size as a definition parameter?
> Why does VARCHAR need length specification?
> What is the default size of a varchar2 input to Oracle stored procedure,and can it be changed?
> Why using anything else but VARCHAR2(4000) to store strings in an Oracle database?
> Why does an oracle plsql varchar2 variable need a size but a parameter does not?
> Ask Tom问题:“我与建模组合作,他们希望定义每个varchar2字段的最大长度.”

我讨论过这个问题的唯一地方是APC在answer中的第3点和第4点:

The database uses the length of a variable when allocating memory for PL/sql collections. As that memory comes out of the PGA supersizing the variable declaration can lead to programs failing because the server has run out of memory.

There are similar issues with the declaration of single variables in PL/sql programs,it is just that collections tend to multiply the problem.

例如. Oracle PL / sql编程,第5版作者:Steven Feuerstein没有提到声明varchar2变量太长的任何缺点,所以它不是一个严重的错误,对吧?

更新

经过一些谷歌搜索后,我发现Oracle文档在发布期间已经发展:

引用PL / sql用户指南和参考10g第2版Chapter 3 PL/SQL Datatypes

Small VARCHAR2 variables are optimized for performance,and larger ones are optimized for efficient memory use. The cutoff point is 2000 bytes. For a VARCHAR2 that is 2000 bytes or longer,PL/sql dynamically allocates only enough memory to hold the actual value. For a VARCHAR2 variable that is shorter than 2000 bytes,PL/sql preallocates the full declared length of the variable. For example,if you assign the same 500-byte value to a VARCHAR2(2000 BYTE) variable and to a VARCHAR2(1999 BYTE) variable,the former takes up 500 bytes and the latter takes up 1999 bytes.

引用PL / sql用户指南和参考11g第1版Chapter 3 PL/SQL Datatypes

For a CHAR variable,or for a VARCHAR2 variable whose maximum size is less than 2,000 bytes,PL/sql allocates enough memory for the maximum size at compile time. For a VARCHAR2 whose maximum size is 2,000 bytes or more,PL/sql allocates enough memory to store the actual value at run time. In this way,PL/sql optimizes smaller VARCHAR2 variables for performance and larger ones for efficient memory use.

For example,if you assign the same 500-byte value to VARCHAR2(1999 BYTE) and VARCHAR2(2000 BYTE) variables,PL/sql allocates 1999 bytes for the former variable at compile time and 500 bytes for the latter variable at run time.

但PL / sql用户指南和参考11g第2版Chapter 3 PL/SQL Datatypes不再提及内存分配,我根本找不到任何有关内存分配的信息. (我正在使用此版本,因此我只检查了11.2文档.)PL / sql用户指南和参考12c版本1 Chapter 3 PL/SQL Datatypes也是如此.

我还发现Jeffrey Kemp的an answer解决了这个问题.但Jeffrey的回答是指10.2文档,问题根本不是PL / sql.

当Oracle实施不同的优化时,看起来这是PL / sql功能在版本上发展的领域之一.

请注意,这也意味着OP中列出的一些答案也是特定于发布的,即使这些问题/答案中没有明确提及.当时间过去并使用较旧的Oracle版本结束时(我在做白日梦?),这些信息将会过时(可能需要几十年的时间).

上面的结论由第12章调整PL / sql语言参考11g R1 PL / sql应用程序中的以下quote支持

Declare VARCHAR2 Variables of 4000 or More Characters

You might need to allocate large VARCHAR2 variables when you are not sure how big an expression result will be. You can conserve memory by declaring VARCHAR2 variables with large sizes,such as 32000,rather than estimating just a little on the high side,such as by specifying 256 or 1000. PL/sql has an optimization that makes it easy to avoid overflow problems and still conserve memory. Specify a size of more than 4000 characters for the VARCHAR2 variable; PL/sql waits until you assign the variable,then only allocates as much storage as needed.

11g R212c R1版本的文档中不再提及此问题.这符合第3章PL / sql数据类型的演变.

回答:

从11gR2开始,它与使用varchar2(10)或varchar2(32767)的内存使用没有区别. Oracle PL / sql编译器将以最佳方式为您处理脏信息!

对于11gR2之前的版本,有一个截止点,其中使用了不同的内存管理策略,每个版本的PL / sql语言参考中都清楚地记录了这一点.

当没有可以从问题域派生的自然长度限制时,上述内容仅适用于PL / sql专用变量.如果varchar2-variable表示GTIN-14,那么应该将其声明为varchar2(14).

当带有表列的PL / sql变量接口使用%type-attribute时,这是使PL / sql代码数据库结构保持同步的零工作方式.

记忆测试结果:

我在Oracle Database 11g企业版11.2.0.3.0版中运行内存分析,结果如下:

str_size iterations UGA   PGA
-------- ---------- ----- ------
10       100        65488 0
10       1000       65488 65536
10       10000      65488 655360
32767    100        65488 0
32767    1000       65488 65536
32767    10000      65488 655360

因为PGA更改是相同的并且仅依赖于迭代而不是str_size,所以我认为varchar2声明的大小无关紧要.虽然测试可能太天真了 – 欢迎评论

测试脚本:

-- plsql_memory is a convenience package wrapping sys.v_$mystat s and
-- sys.v_$statname tables written by Steven Feuerstein and available in the
-- code-zip file accompanying his book.

set verify off

define str_size=&1
define iterations=&2

declare
  type str_list_t is table of varchar2(&str_size);
begin
  plsql_memory.start_analysis;

  declare
    v_strs str_list_t := str_list_t();
  begin
    for i in 1 .. &iterations
    loop
      v_strs.extend;
      v_strs(i) := rpad(to_char(i),10,to_char(i));
    end loop;
    plsql_memory.show_memory_usage;
  end;

end;
/

exit

测试运行示例:

$sqlplus -SL <CONNECT_STR> @memory-test.sql 32767 10000

Change in UGA memory: 65488 (Current = 1927304)
Change in PGA memory: 655360 (Current = 3572704)

PL/sql procedure successfully completed.

$

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐