或者我应该?
(标题的灵感来自于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
之间的区别也很明显:
我讨论过这个问题的唯一地方是APC answer中的第3点和第4点:
数据库在为PL / SQL集合分配内存时使用变量的长度。由于内存来自PGA超大变量声明可能导致程序失败,因为服务器内存不足。
PL / SQL程序中单个变量的声明存在类似的问题,只是集合倾向于使问题成倍增加。
E.g。 Oracle PL / SQL编程,第5版作者:Steven Feuerstein没有提到声明过长的varchar2
变量的任何缺点,所以它不是一个严重的错误,对吗?
更新
经过一些谷歌搜索后,我发现Oracle文档在发布期间已经发展:
来自PL / SQL用户指南和参考10g第2版Chapter 3 PL/SQL Datatypes的引用:
小VARCHAR2变量针对性能进行了优化,而较大的变量针对高效内存使用进行了优化。截止点是2000字节。对于2000字节或更长的VARCHAR2,PL / SQL动态分配足够的内存来保存实际值。对于短于2000字节的VARCHAR2变量,PL / SQL预先分配变量的完整声明长度。例如,如果将相同的500字节值分配给VARCHAR2(2000 BYTE)变量和VARCHAR2(1999 BYTE)变量,则前者占用500个字节,后者占用1999个字节。
来自PL / SQL用户指南和参考11g第1版Chapter 3 PL/SQL Datatypes的引用:
对于CHAR变量或最大大小小于2,000字节的VARCHAR2变量,PL / SQL在编译时为最大大小分配足够的内存。对于最大大小为2,000字节或更多的VARCHAR2,PL / SQL会分配足够的内存来存储运行时的实际值。通过这种方式,PL / SQL可以优化较小的VARCHAR2变量以获得性能,而较大的变量则可以有效地使用内存。
例如,如果为VARCHAR2(1999 BYTE)和VARCHAR2(2000 BYTE)变量分配相同的500字节值,则PL / SQL在编译时为前一个变量分配1999个字节,为后一个变量分配500个字节运行时间。
但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。
答案 0 :(得分:5)
当Oracle实施不同的优化时,看起来这是PL / SQL功能在版本上发展的领域之一。
请注意,这也意味着OP中列出的一些答案也是特定于发布的,即使这些问题/答案中没有明确提及。当时间过去并使用较旧的Oracle版本结束时(我在做白日梦?),这些信息将会过时(可能需要几十年的时间)。
上面的结论由第12章调整PL / SQL语言参考11g R1 的PL / SQL应用程序中的以下quote支持:< / p>
声明4000个或更多字符的VARCHAR2变量
当您不确定表达式结果有多大时,可能需要分配大型VARCHAR2变量。您可以通过声明大尺寸的VARCHAR2变量(例如32000)来节省内存,而不是估计高端的一些变量,例如通过指定256或1000. PL / SQL具有一个优化,可以轻松避免溢出问题和仍然保存记忆。为VARCHAR2变量指定大于4000个字符的大小; PL / SQL在您分配变量之前一直等待,然后只根据需要分配尽可能多的存储空间。
该文档的11g R2和12c R1版本不再提及此问题。这与第3章PL / SQL数据类型的演变一致。
<强>答案:强>
从11gR2开始,与使用varchar2(10)
或varchar2(32767)
的内存使用没有区别。 Oracle PL / SQL编译器将以最佳方式为您处理脏信息!
对于11gR2之前的版本,有一个截止点,使用不同的内存管理策略,每个版本的 PL / SQL语言参考都清楚地记录了这一点。
以上仅适用于没有可从问题域派生的自然长度限制的PL / SQL专用变量。如果varchar2变量代表GTIN-14,则应将其声明为varchar2(14)
。
当带有表列的PL / SQL变量接口使用%type
- 属性时,这是使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更改是相同的并且仅依赖于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
测试运行示例:
$ 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.
$
答案 1 :(得分:1)
我认为问题与任何其他软件一样:分配太多内存会降低性能和失败的可能性,因为它占用了所有内存。
在我看来,尽可能多地使用%type
,因为它可以在更改数据类型或长度时防止错误,并明确该变量的来源。
答案 2 :(得分:1)
也许是因为我在这个时代已经成熟,当时任何系统的最大内存都是48k,然后是快乐的日子,最多可达到64k。它不是虚拟的,你分配的是你得到的(wyaiwyg)(WAY-WIG?)。我看到很多年轻的程序员都倾向于在设计中保持懒惰,并通过增加内存来隐藏设计缺陷。
如果我们养成只要在定义字符串变量时输入varchar2(MAX)
的习惯,我们就不再考虑长度了。但有时长度很重要。如果我们还没有这样做,只要我们输入(
,我们就应该停下来思考一下它真正需要的大小。尺寸在这里重要吗?如果是这样,什么是合理的最大值(或最小值)?这迫使我们超越字节,字段和索引到我们正在尝试使用的实际“事物”。这绝不是一个坏主意。
纪律很难。我们应该养成习惯,尽可能地强制执行。良好的数据和代码设计本质上是困难的。我们可以使用一些工具和技术使它更容易一些,但我们不应该只是因为它更容易做任何事情。这是走向黑暗面的道路,它迟早会赶上我们。