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

use*_*735 9 oracle plsql

或者我应该?

(标题的灵感来自于Gary Myers的评论为什么Oracle varchar2有一个强制大小作为定义参数?)

考虑以下变量:

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;
/
Run Code Online (Sandbox Code Playgroud)

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

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

有很多问题涉及varchar2SQL中的长度语义,并解释了为什么SQL varchar2(4000)中的不良实践.此外,SQL和PL/SQL varchar2-type 之间的区别很好:

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

在为PL/SQL集合分配内存时,数据库使用变量的长度.由于内存来自PGA超大变量声明可能导致程序失败,因为服务器内存不足.

PL/SQL程序中单个变量的声明存在类似问题,只是集合倾向于使问题成倍增加.

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

更新

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

引用PL/SQL用户指南和参考10g第2版第3章PL/SQL数据类型:

小VARCHAR2变量针对性能进行了优化,而较大的变量针对高效内存使用进行了优化.截止点是2000字节.对于2000字节或更长的VARCHAR2,PL/SQL动态分配足够的内存来保存实际值.对于短于2000字节的VARCHAR2变量,PL/SQL预先分配变量的完整声明长度.例如,如果将相同的500字节值分配给VARCHAR2(2000 BYTE)变量和VARCHAR2(1999 BYTE)变量,则前者占用500个字节,后者占用1999个字节.

引用PL/SQL用户指南和参考11g第1版第3章PL/SQL数据类型:

对于CHAR变量或最大大小小于2,000字节的VARCHAR2变量,PL/SQL在编译时为最大大小分配足够的内存.对于最大大小为2,000字节或更多的VARCHAR2,PL/SQL会分配足够的内存来存储运行时的实际值.通过这种方式,PL/SQL可以优化较小的VARCHAR2变量以获得性能,而较大的VARCHAR2变量则可以有效地使用内存.

例如,如果为VARCHAR2(1999 BYTE)和VARCHAR2(2000 BYTE)变量分配相同的500字节值,则PL/SQL在编译时为前一个变量分配1999个字节,在运行时为后一个变量分配500个字节.

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

我也找到 Jeffrey Kemp 的答案,也解决了这个问题.但Jeffrey的回答是指10.2文档,问题根本不是PL/SQL.

use*_*735 5

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

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

结论上述备份用以下报价从第12章调整PL/SQL程序性能PL/SQL语言参考11克R1:

声明4000个或更多字符的VARCHAR2变量

当您不确定表达式结果有多大时,可能需要分配大型VARCHAR2变量.您可以通过声明大尺寸的VARCHAR2变量(例如32000)来节省内存,而不是估计高端的一些变量,例如通过指定256或1000. PL/SQL具有一个优化,可以轻松避免溢出问题和仍然保存记忆.为VARCHAR2变量指定大于4000个字符的大小; PL/SQL等待您分配变量,然后根据需要分配尽可能多的存储空间.

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

回答:

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

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

当没有可以从问题域派生的自然长度限制时,上述内容仅适用于PL/SQL专用变量.如果varchar2变量代表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
Run Code Online (Sandbox Code Playgroud)

因为PGA更改是相同的并且仅依赖于iterations而不是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
Run Code Online (Sandbox Code Playgroud)

测试运行示例:

$ 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.

$
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

3851 次

最近记录:

11 年,7 月 前