N功能是否会导致现有查询出现问题?

我们使用Oracle 10gOracle 11g

我们还有一个图层用于自动编写查询,这些查询来自用.net编写的伪SQL代码(类似于SqlAlchemy for Python)。

我们目前一层包裹在单引号中的任何字符串' ,如果包含非ANSI字符,它会自动组成UNISTR书面为Unicode字节(如特殊字符0E0 )。

现在我们创建了一个用以下构造执行多个插入的方法:
INSERT INTO ... (...) SELECT ... FROM DUAL UNION ALL SELECT ... FROM DUAL ...

这个算法可以组成查询,其中相同的字符串字段有时会作为'my simple string'传递,有时会包装为UNISTR('my string with special chars like 0E0')

描述的条件导致ORA-12704: character set mismatch

一种解决方案是使用INSERT ALL构造,但与现在使用的构造相比,它非常慢

另一种解决方案是指示我们的图层将N放在任何字符串的前面(除了已经用UNISTR包装的字符串)。 这很简单。

我只想知道这是否会对现有查询造成任何副作用。

注意:数据库上的所有字段都是NCHARNVARCHAR2


Oracle编号:http://docs.oracle.com/cd/B19306_01/server.102/b14225/ch7progrunicode.htm


基本上你问的是,字符串是如何存储的,有没有N函数。

你可以检查自己考虑:

SQL> create table test (val nvarchar2(20));

Table TEST created.

SQL> insert into test select n'test' from dual;

1 row inserted.

SQL> insert into test select 'test' from dual;

1 row inserted.

SQL> select dump(val) from test;
DUMP(VAL)                                                                      
--------------------------------------------------------------------------------
Typ=1 Len=8: 0,116,0,101,0,115,0,116                                            
Typ=1 Len=8: 0,116,0,101,0,115,0,116  

正如你所看到的一样,没有副作用。

这个作品如此精美的原因在于unicode的优雅

如果你对这里感兴趣,这是一个很好的视频解释它

https://www.youtube.com/watch?v=MijmeoH9LT4


我假设你得到一个错误"ORA-12704: character set mismatch"因为你的数据在引号内被认为是char而你的字段是nchar,所以char使用不同的字符集进行整理,一个使用NLS_CHARACTERSET ,另一个使用NLS_NCHAR_CHARACTERSET

当您使用UNISTR函数时,它会将数据从char转换为nchar (在任何情况下也会将编码值转换为字符),如Oracle文档所述:

“UNISTR以文本字面或表达式来解析字符数据并将其返回到国家字符集中。”

使用NTO_NCHAR显式转换值时,只能在NLS_NCHAR_CHARACTERSET获取值而不解码。 如果你有一些像这样编码的值"0E0"它们将不会被解码,并且会被认为是不变的。

所以如果你有一个插入如:

   insert into  select N'my string with special chars like 0E0', 
    UNISTR('my string with special chars like 0E0') from dual ....

您在第一个插入字段中的数据将为: 'my string with special chars like 0E0'而不是'my string with special chars like à' 。 这是我意识到的唯一副作用。 其他查询应该已经使用NLS_NCHAR_CHARACTERSET编码,因此使用显式转换不应该有任何问题。

顺便说一句,为什么不直接插入所有的值作为N'my string with special chars like à' ? 如果您在'上一级'软件中使用不同的编码,只需将它们编码为UTF-16(我假设您使用UTF-16作为nchars)。


  • 使用n函数 - 你已经有了上面的答案。
  • 如果你有机会改变数据库的字符集,那真的会让你的生活更轻松。 我正在研究庞大的生产系统,并发现这样一个趋势,即由于存储空间便宜,每个人都转向AL32UTF8,国际化的麻烦慢慢变成过去的痛苦回忆。

    我发现最简单的事情就是使用AL32UTF8作为数据库实例的字符集,并且随处使用varchar2。 我们通过JDBC将标准Java unicode字符串作为绑定变量读取和写入,没有任何伤害,并且小提琴。

    由于多种原因,构建大量SQL插入文本的想法可能无法很好地扩展:

  • 有一个固定长度的最大允许SQL语句 - 所以它不适用于10000个插入
  • 建议使用绑定变量(然后你没有n'xxx与unistr混乱)
  • 动态创建新的SQL语句的想法是非常资源性的。 它不允许Oracle为任何事情缓存任何执行计划,并会使Oracle在每次调用时都很难分析您的looong语句。
  • 你试图实现的是一个质量插入。 使用Oracle驱动程序的JDBC批处理模式轻松执行该操作,请参阅:http://viralpatel.net/blogs/batch-insert-in-java-jdbc/

    请注意,插入速度也受触发器(必须执行)和外键约束(必须验证)的影响。 因此,如果您要插入数以千计的行,请考虑禁用触发器和外键约束,并在插入后启用它们。 (您将失去触发器调用,但插入后的约束验证可能会产生影响。)

    还要考虑回滚段大小。 如果您插入了一百万条记录,那将需要一个巨大的回滚段,这可能会导致存储介质上的严重交换。 在每个1000条记录之后提交是一个很好的经验法则。

    (Oracle使用版本控制而不是共享锁,因此具有未提交更改的表始终可用于读取.1000条记录提交率意味着每秒大约1次提交 - 足够慢以利于写入缓冲区,但速度足以不干扰其他人愿意更新同一张表。)

    链接地址: http://www.djcxy.com/p/32503.html

    上一篇: Can N function cause problems with existing queries?

    下一篇: Generic parameters declaration in static member