VARCHAR最大长度为4000,但只能存储2666字节长的泰语文本

时间:2014-01-27 12:49:28

标签: sql oracle oracle11g

我正在使用带有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. 在尝试将文本插入表格之前,我能否知道文本的真正限制? (假设文本是泰语和英语,也可能也有不同的语言)
  3. 重要提示:因为我需要支持一个非常庞大且功能正常的系统,我无法将数据类型切换到俱乐部,但它可以解决问题。

    感谢您的帮助。


    修改

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

1 个答案:

答案 0 :(得分:6)

问题

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

情况高达11g

不幸的是,VARCHAR2列的最大大小存在硬性限制。它是4000 BYTE(!)(参见Oracle数据库参考,章节Oracle Datatypes),直到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触发器,你可能会失去一些限制,但它可能对你有用。

相关问题