Oracle 19c 新特性|增加 VARCHAR2 数据类型的大小限制
作者 | JiekeXu
来源 |公众号 JiekeXu DBA之路(ID: JiekeXu_IT)
如需转载请联系授权 | (个人微信 ID:JiekeXu_DBA)
大家好,我是 JiekeXu,很高兴又和大家见面了,今天和大家一起来学习 Oracle 19c 新特性,欢迎点击上方蓝字“JiekeXu DBA之路”关注我的公众号,标星或置顶,更多干货第一时间到达!
经朋友介绍,我读完 Tim Hall 于 2022 年 9 月 27 日他的博客上发表的博文。得到了一些关于 Oracle 社区的信息,10 月 11 日星期二是 “Oracle 社区活动日”,但在 2021 年,它被重命名为“乔尔·卡尔曼日”。乔尔对社区很感兴趣,这是对他的致敬。所以许多人和朋友都在这一日写各种有趣的帖子并带上 #JoelKallmanDay 标签来纪念他.
这无疑对社区的每个人都有很大的情感意义。所以,推荐我写的朋友也呼唤我也写点东西来支持这个活动。但是写什么呢?由于这是我第一次写,所以就写一个 Oracle 新特性吧。于是乎就用我蹩脚的英语加有道词典花了两个晚上写了人生中第一篇英文博客《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/)。并且第二日 Tim Hall 大师(https://oracle-base.com/misc/site-info#biog) 将来自全球的六、七十位社区伙伴的博客汇总到一起(https://oracle-base.com/blog/),如下,我的文章刚好被排在第六位。
下面我打算在原有英文的基础上修改修改,翻译回中文,使读起来更顺畅,排版更美观。
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 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@JiekeXu> create table T1(C clob, E varchar2(32737));
Table created.
14:03:09 SYS@JiekeXu> 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@JiekeXu> commit;
Commit complete.
14:03:19 SYS@JiekeXu> set autot trace stat
14:04:04 SYS@JiekeXu> select C from t1;
DB Version 19.3
(db 19.3)
DB Version 12.2
(db 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语句在建表时就抛出了一个数据类型太长的错误。
(db 12.1.0.2)
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 脚本再正常重启数据库。vatchar2 最多可以存储 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;
Summary 总结
扩展数据类型
从 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。
全文完,希望可以帮到正在阅读的你,如果觉得有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~
❤️ 欢迎关注我的公众号【JiekeXu DBA之路】,一起学习新知识!
————————————————————————————
公众号:JiekeXu DBA之路
CSDN :https://blog.csdn.net/JiekeXu
墨天轮:https://www.modb.pro/u/4347
腾讯云:https://cloud.tencent.com/developer/user/5645107
————————————————————————————