暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 从max_string_size标准导出数据泵架构,导入到max_string_size Extended => ORA-01450: 超过最大密钥长度 (6398)

ASKTOM 2020-03-25
1031

问题描述

嗨,甲骨文大师团队

我在具有charset AL32UTF8和max_string_size标准的源数据库版本12.1.0.2中有一个架构。
有些表具有列VARCHAR2(2000 CHAR),原则上这可能意味着多达8000个字节,但这里的最大值是4000的,这反映了user_tab_columns中的DATA_LENGTH。
因此,一些具有大量4字节UTF字符的文本可能不适合甚至少于2000个字符,但在实践中,它不是一个普通文本与几个UTF字符的问题。
这些列中有几个被索引,这是没有问题的,因为4000字节的最大限制。

我正在datapump导出此架构并将其导入目标数据库版本19.3中,其中包含charset AL32UTF8和max_string_size扩展。
由于扩展的max_string_size,这些由导入创建的VARCHAR2(2000 CHAR) 列现在具有8000的DATA_LENGTH!
(原则上很好,因为现在没有1942字符串无法容纳的风险;-)

问题是,这些列不能再索引了。
我在datapump导入日志中得到 “ORA-01450: 超过最大密钥长度 (6398)”。

文档指出不可能将max_string_size从扩展更改为标准,因此我无法更改目标数据库。
另外,我真的不想这样做,因为此数据库中的其他模式很可能会从使用Extended中受益。
但是对于这个模式,我希望将这些列的DATA_LENGTH保持足够低 (4000字节),以允许它们被索引。

如果我将列更改为VARCHAR2(4000字节),则允许索引。
但是数据库将允许UTF字符串超过2000个字符,对吗?(只要大多数字符都是1字节的UTF。)
这可能会破坏前端应用程序。

我正在考虑VARCHAR2(4000字节) 与检查约束长度c (col) <= 2000。
您会看到不利的一面吗?

是否有一种在datapump导入期间转换这些列的方法?
还是简单地忽略ORA-01450错误,在导入后更改列,然后创建索引的最佳方法?

还有其他可能有益的想法或提示吗?

谢谢...


啦啦队
/金

专家解答

But the database would then allow UTF strings longer than 2000 characters, right?

是的,确实会:

create table t (
  c1 varchar2(2000 char),
  c2 varchar2(4000 byte)
);

insert into t values ( 'x', rpad ( 'x', 4000, 'x' ) );

select lengthc ( c2 ) from t;

LENGTHC(C2)   
          4000 
复制


I'm considering VARCHAR2(4000 BYTE) with a check constraint LENGTHC(col) <= 2000.
Would you see a downside to this?


无法想到任何事情; 由于现有的应用程序已经仅限于2,000个字符,因此不应该出现功能问题。我主要关心的是 “惊喜因素”。也就是说,这是不寻常的事情,所以将来可能会赶上开发人员/dba。

Or is the best way simply to ignore the ORA-01450 errors, alter the columns after the import, and then create the indexes?

这是一个选择;)

您可以通过在索引定义中使用SUBSTR或STANDARD_HASH来解决该问题。优化器可以在不改变查询的情况下使用标准哈希函数进行相等:

create index i2 
  on t ( standard_hash ( c2 ) );
  
insert into t values ( 'c1', 'c2' );

set serveroutput off
select * from t
where  c2 = 'c2';

select * 
from   dbms_xplan.display_cursor(format => 'BASIC LAST +PREDICATE');

----------------------------------------------------                        
| Id  | Operation                           | Name |                        
----------------------------------------------------                        
|   0 | SELECT STATEMENT                    |      |                        
|*  1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T    |                        
|*  2 |   INDEX RANGE SCAN                  | I2   |                        
----------------------------------------------------                        
                                                                            
Predicate Information (identified by operation id):                         
---------------------------------------------------                         
                                                                            
   1 - filter(("C2"='c2' AND INTERNAL_FUNCTION("T"."C1")))                  
   2 - access("T"."SYS_NC00003$"=HEXTORAW('6B1F53303A732CCC8C6AAE6640399    
              827C15250E3'))     
复制


您可以在文档中阅读有关此内容的更多信息https://docs.oracle.com/en/database/oracle/oracle-database/20/sqlrf/CREATE-INDEX.html#GUID-1F89BBC0-825F-4215-AF71-7588E31D8BFE

Any other ideas or tips that might be beneficial?

问题是索引键的数据必须小于索引块大小减去一些开销。所以还有另一种解决方法:

将索引放在具有更大块大小的表空间中!

create index i 
  on t ( c1 );
  
ORA-01450: maximum key length (6398) exceeded

sho parameter db_16K_cache_size

NAME              TYPE        VALUE 
----------------- ----------- ----- 
db_16k_cache_size big integer 16M   

sho parameter max_string

NAME            TYPE   VALUE    
--------------- ------ -------- 
max_string_size string EXTENDED 

create tablespace tblsp_16k 
  datafile 'tblsp_32k' size 1M
  blocksize 16384;

create index i 
  on t ( c1 )
  tablespace tblsp_16k;
  
select tablespace_name 
from   user_indexes
where  index_name = 'I';

TABLESPACE_NAME   
TBLSP_16K       
复制


注意您需要将适当的缓存大小设置为非零值。这也增加了数据库的 “惊喜因子”。我更喜欢基于函数的索引方法之一,而不是这个。
文章转载自ASKTOM,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论