4

我有一个大约 100.000 行的表,过去看起来或多或少像这样:

id      varchar(20),
omg     varchar(10),
ponies  varchar(3000)

添加对国际字符的支持时,我们必须将ponies列重新定义为 nclob,因为 3000(多字节)字符对于 nvarchar 来说太大了

id      varchar(20),
omg     varchar(10),
ponies  nclob 

我们使用 java 中的准备语句从表中读取:

select omg, ponies from tbl where id = ?

在 'ponies' 列更改为 NCLOB 并且其他一些表更改为使用 nchar 列之后,Oracle 11g 决定执行全表扫描而不是使用id列的索引,这导致我们的应用程序停止运行。

向查询添加提示时,使用索引并且一切都“很好”,或者只是比列是 varchar 时慢一点。

我们定义了以下连接属性:

 oracle.jdbc.convertNcharLiterals="true"
 defaultNChar=true

顺便说一句,数据库统计信息已更新。

我没有时间查看所有查询,所以我不知道是否忽略了其他索引,但我是否必须担心 defaultNChar 设置会以某种方式混淆优化器,因为 id 不是 nchar?在几乎所有查询上添加提示或重新定义所有键都是相当尴尬的。

或者,全表扫描是否被视为微不足道,因为将要加载“大” nclob - 该假设似乎偏离了 3 个数量级,我想相信 Oracle 比这更聪明。

还是只是运气不好?或者是其他东西?是否可以在没有提示的情况下修复?

4

3 回答 3

3

问题原来是 jdbc-flag defaultNChar=true。

如果参数作为 nchar/nvarchar 发送,Oracles 优化器将不会使用在 char/varchar2 列上创建的索引。这几乎是有道理的,因为我想你可能会得到幻影结果。

我们主要使用存储过程,参数定义为 char/varchar2 - 在执行查询之前强制转换 - 所以我们没有注意到这种效果,除非在一些使用动态 sql 的地方。

解决方案是将数据库转换为 AL32UTF8 并去掉 nchar 列。

于 2012-01-28T22:07:11.247 回答
2

当您重做统计数据时,您估计或使用dbms_stats.gather_table_stats的估计百分比 > 50%?如果您没有使用 dbms_stats 和 100% 的估计百分比。

如果您的表只有 3 列并且这些是您要返回的列,那么最好的索引是所有 3 列,无论您提示什么,即使id索引是唯一的。就目前而言,您的解释计划应该是一个唯一的索引扫描,然后是一个按 rowid 的表访问。如果您索引所有 3 列,这将成为唯一扫描,因为您返回的所有信息都将在索引中,并且无需重新访问表来获取它。顺序是id, omg, ponies在 where 子句中使用它。这将有效地使您的表成为一个index organized table,这比拥有一个单独的索引更容易。显然,之后收集统计数据。

说了这么多,我实际上不确定您是否可以索引 nclob,并且无论您做什么,列的大小都会产生影响,因为它越长,您必须执行的磁盘读取就越多。

于 2011-10-10T23:26:49.730 回答
0

抱歉,但我不明白您为什么要将列小马从 varchar 更改为 clob。如果此列中的最大长度为 3000 个字符,为什么不使用 NVARCHAR2 列呢?据我所知,nvarchar2 最多可以容纳 4000 个字符。

但是您是对的,当国家字符集为 AL16UTF16 时,允许的最大列大小为 2000 个字符,而当它是 UTF8 时,允许的最大列大小为 4000 个字符。

于 2011-10-11T06:55:47.180 回答