【问题标题】:VARCHAR max length is 4000 but only 2666 byte long Thai text can be storedVARCHAR 最大长度为 4000,但只能存储 2666 字节长的泰文文本
【发布时间】:2014-02-18 07:41:53
【问题描述】:

我正在使用带有 PL/SQL 的 Oracle 数据库 11g。程序是用 C#、.NET 4 编写的。

我有一个带有 varchar(4000) 列的表,我想在 DB 中存储一个泰语文本。 我发现当我尝试存储长度超过 1333 的泰语文本时,Oracle 会抛出异常,尽管最大长度为 4000:

ORA-01461:只能绑定 LONG 值以插入到 LONG 列中

我还注意到,当我以较小的限制工作时,它会按预期工作。即:varchar(10) - 允许长度为 10 的值和更长的文本抛出异常:

ORA-01401 插入的值对于列来说太大

根据我已经进行的测试,我可以假设从数字“X”开始,oracle 停止计算实际字母的长度。相反,它会乘以最长字母长度值中的字母数(在泰语中,最长字母的长度是 3 - 意味着它就像 3 个字符),所以 1333 * 3 = 3999 我只能添加另一个字符(使用类似的语言英文)。

我的问题:

  1. 为什么不同最大长度的行为会有所不同?
  2. 在尝试将文本插入表格之前,我能否知道文本的真正限制? (假设文本是泰语和英语,也可能是不同的语言)

重要提示:因为我需要支持一个非常大且功能强大的系统,所以我无法将数据类型切换到俱乐部,但它会解决问题。

感谢您的帮助。


编辑

我计算这 1333 个字符的字节数。它们的字节长度为 2666,仍然小于 4000。我知道最大长度以字节为单位,但我不明白为什么会出现上述异常。 我用:System.Text.ASCIIEncoding.Unicode.GetByteCount(text) 来检查字节数。

【问题讨论】:

  • 4000 表示 4000 个 字节 不是字符。如果您使用的是多字节字符集,则一个字符最多可以包含 4 个字节(取决于字符集) 使用varchar 列无法克服此限制。如果您需要更多,则需要使用CLOB
  • 你的数据库的 NLS_CHARACTERSET 设置是什么?您是否考虑过NVARCHAR2 列?
  • @Wooble:NVARCHAR2 列也限制为 4000 字节
  • 存储在数据库中的 1333 个字母的字节数为 2668 - 小于 4000。另外,nvarchar 也有同样的问题。
  • @hadaco: 用什么编码? UTF-8 对所有泰语字符使用 3 个字节。

标签: sql oracle oracle11g


【解决方案1】:

问题

在描述 VARCHAR 时,您应该提供一个单位,例如VARCHAR2(200 BYTE)VARCHAR2(200 CHAR)。如果省略单位,则默认为 BYTE(请参阅 Oracle 数据库概念,章节 Oracle Datatypes)。这似乎是一个小细节,但当您有多字节字符集时会变得非常严重。

情况高达 11g

很遗憾,VARCHAR2 列的最大大小存在硬性限制。在 Oracle 11g 和 .这是一个硬性限制,没有办法解决这个问题。解决此问题的唯一方法是使用 CLOB 列。

12c 的解决方案

Oracle 12c 的情况有所不同。在那里,您可以使用参数 MAX_STRING_SIZE = EXTENDED 将限制提升到 32767 BYTE(请参阅 Oracle 数据库语言参考,Data Types 章和 Oracle 数据库参考,Initialization Parameters 章)。所以显而易见的解决方案是:升级到 Oracle 12c,设置 MAX_STRING_SIZE = EXTENDED according to the documentation 并更改表定义。更改表时,您可能会丢失一些索引,因为在 12c 之前,非索引不能保存超过 4000 BYTE 的 VARCHAR2 值,并且可能仍然存在一些限制。 (我必须检查索引的问题,是否可以通过重建索引来解决)。

解决方案:更改数据库编码

您可以尝试更改本机数据库编码(数据库将 CHAR 映射到 BYTE 的方式)。为此,您通常必须创建一个新数据库并为 NLS_CHARACTERSET 提供适当的参数。这是数据库操作方式的一个非常大的变化,并且可能会产生一些副作用。如果您曾经尝试以不同的编码添加字符,那么您可能会不走运(即您无法将它们存储在数据库中)。所以我不建议这个解决方案。

解决方案:切换到 CLOB

通常没有必要对如此大的文本字段提供任意查询。您可能会尝试识别在大文本列上选择的查询并将它们迁移到 CLOB 列上的Oracle Text。但这是一个非常大的变化,您现有的模式或应用程序可能无法实现。您最终可能会得到一堆“INSTEAD OF”触发器并缺少一些约束检查(涉及新创建的 CLOB 列)。

解决方案:使用 XML

您可以尝试将字符串存储为 XML 列,而不是 CLOB。这些文件的最大大小为 4GB。它会损害你的表现,你必须提供 INSTEAD OF 触发器,你可能会失去一些限制,但它可能对你有用。

【讨论】:

  • 请注意,在 Oracle 12c 中,VARCHAR2 的限制已提高到 32767 字节。
  • 谢谢!我相应地改变了答案。
  • 做得很好,但不确定您的陈述“索引不能保存超过 4000 BYTE 的 VARCHAR2 值” - 我很确定它们可以,否则 12c 将被视为损坏。只是一些功能索引可能会变得无法使用,但可以修复。
  • 好的,我必须检查关于 12c 上的索引的声明。
  • 大 (>4000 BYTE) 列的索引工作正常。根据文档,功能索引可能存在问题,您将无法获得工作索引。但我无法重现该问题。
猜你喜欢
  • 1970-01-01
  • 2011-04-26
  • 2016-06-18
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 2019-05-15
  • 2013-02-16
  • 2015-02-02
相关资源
最近更新 更多