Oracle 19c对VARCHAR2的限制
Posted bisal(Chen Liu)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle 19c对VARCHAR2的限制相关的知识,希望对你有一定的参考价值。
Oracle每个新的版本都会带来一些新的特性,或者对现有功能的扩展,例如传统的VARCHAR2数据类型支持4000字节,从12c开始,就可以扩展长度(可参考《支持超过4000字节的varchar2类型》)。
JiekeXu老师的这篇文章《Oracle 19c 新特性|增加 VARCHAR2 数据类型的大小限制》讲解了19c中对VARCHAR2数据类型的扩展,而且得到了大牛的推荐,值得学习。
Tim Hall大师(https://oracle-base.com/misc/site-info#biog)将来自全球社区伙伴的博客汇总到一起(https://oracle-base.com/blog/),JiekeXu老师的这篇《Increased Size Limit for VARCHAR2, NVARCHAR2, and RAW Data Types#JoelKallmanDay》文章排在第六位。
链接:https://xiaoqiangxu.wordpress.com/2022/10/11/increased-size-limit-for-varchar2-nvarchar2-and-raw-data-typesjoelkallmanday
下面我打算在原有英文的基础上修改修改,翻译回中文,使读起来更顺畅,排版更美观。
On the Oracle New Features Website, there is a new feature about
extending data types“The maximum size of the VARCHAR2, NVARCHAR2,
and RAW data types has been increased from 4,000 to 32,767 bytes“.
在Oracle新特性网站上(https://apex.oracle.com/database-features/),有一个关于扩展数据类型的新特性“VARCHAR2、NVARCHAR2和RAW数据类型的最大大小已从4000增加到32,767字节”。
我认为它很有趣,很喜欢,也很实用,所以我想介绍它。
以Varchar2数据类型为例,
The VARCHAR2 data type specifies a variable-length character string
in the database character set. You specify the database character
set when you create your database.
VARCHAR2数据类型在数据库字符集中指定一个可变长度的字符串。在创建数据库时指定数据库字符集。
When you create a table with a VARCHAR2 column, you must specify
the column length as size optionally followed by a length qualifier. The
qualifier BYTE denotes byte length semantics while the qualifier
CHAR denotes character length semantics. In the byte length semantics, size
is the maximum number of bytes that can be stored in the column. In
the character length semantics, size is the maximum number of code
points in the database character set that can be stored in the
column. A code point may have from 1 to 4 bytes depending on the
database character set and the particular character encoded by the
code point. Oracle recommends that you specify one of the length
qualifiers to explicitly document the desired length semantics
of the column. If you do not specify a qualifier, the value of the
NLS_LENGTH_SEMANTICS parameter of the session creating the column
defines the length semantics, unless the table belongs to the schema
SYS, in which case the default semantics is BYTE.
当创建带有VARCHAR2列的表时,必须将列长度指定为可选的大小,后面跟着一个长度限定符。限定符BYTE表示字节长度语义,而限定符CHAR表示字符长度语义。在字节长度语义中,size是列中可以存储的最大字节数。在字符长度语义中,size是数据库字符集中可以存储在列中的代码点的最大数量。一个代码点可能有1到4个字节,这取决于数据库字符集和代码点编码的特定字符。Oracle建议您指定一个长度限定符来显式记录列所需的长度语义。如果不指定限定符,则创建列的会话的NLS_LENGTH_SEMANTICS参数的值定义长度语义,除非表属于模式SYS,在这种情况下默认语义为BYTE。
Oracle stores a character value in a VARCHAR2 column exactly as you
specify it, without any blank-padding, provided the value does not
exceed the length of the column. If you try to insert a value that
exceeds the specified length, then Oracle returns an error ORA-12899.
Oracle在VARCHAR2列中存储的字符值与您指定的完全一致,没有任何空白填充,只要该值不超过列的长度。如果试图插入一个超过指定长度的值,Oracle将返回一个ORA-12899:value too large for column “SYS”.“T5”.“E” (actual: 4000, maximum: 3999)错误。
However, in the Oracle 19c official documentation description,
The minimum value of size is 1. The maximum value is
32767 bytes if MAX_STRING_SIZE = EXTENDED
4000 bytes if MAX_STRING_SIZE = STANDARD
但是在Oracle 19c官方文档中,size的最小值是 1。最大值为4000或者32767是需要根据参数MAX_STRING_SIZE的值确定,当值为EXTENDED时,size大小才可以为32767。
While size may be expressed in bytes or characters (code points) the
independent absolute maximum length of any character value that can be
stored into a VARCHAR2 column is 32767 or 4000 bytes, depending on
MAX_STRING_SIZE. For example, even if you define the column length to be
32767 characters, Oracle returns an error if you try to insert a
32767-character value in which one or more code points are wider than 1
byte. The value of size in characters is a length constraint, not
guaranteed capacity. If you want a VARCHAR2 column to be always able to
store size characters in any database character set, use a value of size
that is less than or equal to 8191, if MAX_STRING_SIZE = EXTENDED,
or 1000, if MAX_STRING_SIZE = STANDARD.
虽然大小可以用字节或字符(码位)表示,但可以存储到VARCHAR2列中的任何字符值的独立绝对最大长度是32767或4000字节,这取决于MAX_STRING_SIZE。例如,即使您将列长度定义为32767个字符,如果您试图插入一个32767个字符的值,其中一个或多个编码点的宽度大于1字节,Oracle也会返回一个错误。字符大小的值是长度限制,而不是容量保证。如果希望VARCHAR2列始终能够在任何数据库字符集中存储大小字符,如果 MAX_STRING_SIZE = EXTENDED,则使用小于或等于8191的size值,如果 MAX_STRING_SIZE = STANDARD,则使用小于或等于1000的size值。
However, I found that the MAX_STRING_SIZE parameter does not need to
be set to EXTENDED to create the varchar2 extension data type and
insert the data successfully.The following is my test in
each version of the database. Isn’t it interesting that there is
a discrepancy with the official Oracle documentation?
但是,我发现不需要将MAX_STRING_SIZE参数设置为EXTENDED来创建varchar2扩展数据类型,并成功插入数据。以下是我在每个版本的数据库中的测试。与Oracle官方文档描述的有点差异,这是不是很有趣呢?
DB Version 19.15
DB Version 19.15
DB Version 19.4
sqlplus / as sysdba
set timing on time on
SQL*Plus: Release 19.0.0.0.0 - Production on Mon Oct 10 13:43:15 2022
Version 19.4.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.4.0.0.0
show parameter max_string_size
NAME TYPE VALUE
max_string_size string STANDARD
14:02:42 SYS@bisal> create table T1(C clob, E varchar2(32737));
Table created.
14:03:09 SYS@bisal> insert into t1 select lpad(rownum,32767,'X'),lpad(rownum,32767,'X') from dual connect by level <=10;
10 rows created.
14:03:14 SYS@bisal> commit;
Commit complete.
14:03:19 SYS@bisal> set autot trace stat
14:04:04 SYS@bisal> select C from t1;
DB Version 19.3
DB Version 12.2
Because I don’t have the database versions of Oracle 12.1.0.1 and
12.0.1.2 for the moment, I can’t test it. I wonder whether these
two versions need to set parameters and restart the database.
Interested friends with the environment can test whether the
following results are correct.
因为我当前没有Oracle 12.1.0.1和12.0.1.2的数据库版本,所以我不能测试它。我想知道这两个版本是否需要设置参数并重新启动数据库。对12.1环境感兴趣的朋友可以测试下是否正确,是否需要修改参数并跑utl32k.sql脚本。
So what’s the problem? You know what? Give me a homework assignment.
那么问题是什么呢?你知道吗?继续往下看,后面会揭秘。
So what are the benefits of Extended Data types?
那么扩展数据类型的好处是什么呢?
Increasing the allotted size for these data types allows users to
store more information in character data types before switching to
large objects (LOBs). This is especially useful for brief textual
data types and the capabilities to build indexes on these types
of columns And Extended VARCHAR2 reduces the number of network
round-trips.
增加这些数据类型的分配大小允许用户在切换到大对象(lob)之前在字符数据类型中存储更多的信息。这对于简短的文本数据类型以及在这些类型的列上构建索引的功能尤其有用。Extended VARCHAR2减少了网络往返的数量。
Update on Day 2
Today, my friend sent me a screenshot of version 12.1.0.2.The result is a direct error in the SQL construct sentence.
今天,我的朋友给我发了一张12.1.0.2版本的运行截图。结果是SQL语句在建表时就抛出了一个数据类型太长的错误。
In the test process of version 12.2, it is found that no matter how
large the size is, it can be successfully created.So why is this
happening? Let’s move on.
在12.2版本的测试过程中发现,无论size大小有多大,表都可以成功创建,而且数据也会插入成功。那么,为什么会出现这种情况呢?让我们继续。
Now for the reveal开始揭秘
在我的一台单机的19.12的环境下,创建表进行测试。
create table T1(id int, E varchar2(32767));
CREATE SEQUENCE SEQ_T1 MINVALUE 1 MAXVALUE 99999999999999 INCREMENT BY 1 START WITH 1 CACHE 50 ORDER NOCYCLE;
insert into t1 values(SEQ_T1.nextval,lpad('x',32767,'x'));
insert into t1 values(SEQ_T1.nextval,lpad('x',32768,'x'));
commit;
select length(E) from t1;
And you can see that whether I use 32767 or 32768 I’m going to end up
with a length of 4000.So the official document says there is no
error, we have to modify the parameter MAX_STRING_SIZE = EXTENDED .
你可以看到,无论我用 32767 还是 32768,最终长度都是 4000。所以官方文档说没有错误,我们必须修改参数 MAX_STRING_SIZE = EXTENDED。
(database must in UPGRADE mode)
数据库需要startup UPGRADE以升级模式启动,然后才能修改参数,并且需要跑脚本utl32k.sql,然后关闭数据库再正常重启数据库。
Therefore, it can be seen from the above that under normal
circumstances, the maximum value of varchar2 can only be 4000,
and the excess part will be truncated. After the database is
started in upgrade mode, utl32k.sql is run, and parameters are
modified, vatchar2 can store up to 32767 bytes, and the excess
bytes are truncated.
因此,由上表可以看出,在正常情况下,varchar2的最大值只能为4000,多余的部分会被截断。数据库以升级模式启动后,修改参数,跑utl32k.sql脚本再正常重启数据库。varchar2最多可以存储32767个字节,多余的字节被截断。顺便说一句,NVARCHAR2和RAW在这场景下最多也可以存储32767个字节。
值得注意的是如果您的数据库是RAC,需要关闭node2并修改集群参数CLUSTER_DATABASE=FALSE。如果你的数据库还有ADG备库,请立即修改MAX_STRING_SIZE并重启,否则备库不修改此参数会导致MRP0进程异常宕掉,造成主备数据不同步的情况。
node2: shu immediate
node1:
alter system set CLUSTER_DATABASE=FALSE scope=spfile;
alter system set MAX_STRING_SIZE = EXTENDED scope=spfile;
shu immediate
startup upgrade
@?/rdbms/admin/utl32k.sql
alter system set CLUSTER_DATABASE=TRUE scope=spfile;
shu immediate
startup
show parameter max_string_size
create table T1(E varchar2(32767));
insert into t1 values(lpad(‘x’,32767,’x’));
commit;
select length(E) from t1;
node2: startup
----ADG instance
alter system set CLUSTER_DATABASE=TRUE scope=spfile;
shu immediate
startup
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT;
扩展数据类型
从Oracle Database 12c开始,您可以为VARCHAR2、NVARCHAR2和RAW数据类型指定最大大小为32767字节。可以通过设置初始化参数MAX_STRING_SIZE来控制您的数据库是否支持这个新的最大大小,如下所示:
如果MAX_STRING_SIZE = STANDARD,则适用于Oracle Database 12c之前的版本的大小限制:VARCHAR2和NVARCHAR2数据类型为4000字节,RAW数据类型为2000字节。这是默认设置。
如果MAX_STRING_SIZE = EXTENDED,则VARCHAR2、NVARCHAR2和RAW数据类型的大小限制为32767字节。
声明大小大于4000字节的VARCHAR2或NVARCHAR2数据类型,或声明大小大于2000字节的RAW数据类型,都是扩展数据类型。扩展的数据类型列是在线存储的,利用Oracle的LOB技术。LOB存储始终与表对齐。在使用自动段空间管理(ASSM)管理的表空间中,扩展的数据类型列存储为SecureFiles lob。否则,它们被存储为BasicFiles lob。lob作为存储机制的使用只是内部的。因此,您不能使用DBMS_LOB包操作这些lob。Oracle强烈反对使用BasicFiles lob作为存储机制。BasicFiles lob不仅对扩展数据类型列的功能施加了限制,而且计划在未来的版本中弃用BasicFiles数据类型。
注意,尽管必须设置MAX_STRING_SIZE = EXTENDED才能将RAW数据类型的大小设置为大于2000 字节,但只有当RAW数据类型的大小大于4000字节时,它才被存储为out-of-line LOB。例如,为了声明RAW(3000)数据类型,必须设置MAX_STRING_SIZE = EXTENDED。但是,列是内联存储的。
注意事项:
您可以像使用标准数据类型一样使用扩展数据类型,需要注意以下事项:
1、如果列是扩展数据类型列,则在尝试创建索引时可能会收到“超出最大键长度”错误。索引的最大键长度取决于数据库块大小和存储在块中的一些附加索引元数据。例如,对于使用Oracle标准8K块大小的数据库,最大密钥长度约为6400字节。
要解决这种情况,您必须使用以下方法之一缩短要索引的值的长度:
创建基于函数的索引以缩短存储在扩展数据类型列中的值,作为用于索引定义的表达式的一部分。
创建虚拟列以缩短存储在扩展数据类型列中的值,作为用于虚拟列定义的表达式的一部分,并在虚拟列上构建普通索引。使用虚拟列还使您能够利用常规列的功能,例如收集统计信息以及使用约束和触发器。
对于这两种方法,您都可以使用SUBSTR或者STANDARD_HASH函数来缩短扩展数据类型列的值以构建索引。这些方法具有以下优点和缺点:
使用该SUBSTR函数返回一个子字符串或前缀,column它是索引键可接受的长度。这种类型的索引可用于原始列上的相等、IN-list和范围谓词,而无需将SUBSTR列指定为谓词的一部分。
使用该STANDARD_HASH函数可能会创建一个比基于子字符串的索引更紧凑的索引,并且可能会减少不必要的索引访问。这种类型的索引可用于原始列上的相等和IN-list谓词,而无需将STANDARD_HASH列指定为谓词的一部分。
以下示例显示如何在扩展数据类型列上创建基于函数的索引:
CREATE INDEX index ON table (SUBSTR(column, 1, n));
---- 对于 n,指定一个足够大的前缀长度以区分列中的值。
以下示例显示如何为扩展数据类型列创建虚拟列,然后在虚拟列上创建索引:
ALTER TABLE table ADD (new_hash_column AS (STANDARD_HASH(column)));
CREATE INDEX index ON table (new_hash_column);
2、如果列表分区的分区键列是扩展数据类型列,则希望为分区指定的值列表可能超过分区边界的4K字节限制。有关如何解决此问题的信息,请参阅create table的list_partitions子句。
3、初始化参数的值MAX_STRING_SIZE会影响以下内容:
文本文字的最大长度。有关详细信息,请参阅文本字面量。
连接两个字符串的大小限制。有关详细信息,请参阅串联运算符。
NLSSORT函数返回的排序规则键的长度。请参阅NLSSORT。
对象的某些属性的大小XMLFormat。有关详细信息,请参阅XML格式模型。
以下XML函数中某些表达式的大小:XMLCOLATTVAL、XMLELEMENT、XMLFOREST、XMLPI和XMLTABLE。
如果您认为这篇文章有些帮助,还请不吝点下文章末尾的"点赞"和"在看",或者直接转发pyq,
近期更新的文章:
近期的热文:
文章分类和索引:
以上是关于Oracle 19c对VARCHAR2的限制的主要内容,如果未能解决你的问题,请参考以下文章
Oracle RawToHex 函数 - 如果返回值超过 varchar2 限制会发生啥?