聯機重定義修改欄位型別(NVARCHAR2->VARCHAR2)

space6212發表於2019-06-16
今天在調整一個SQL的時候發現有一個表使用了NVARCHAR2欄位型別,在於VARCHAR2型別的欄位連線時發生隱式轉換(VARCHAR2 -> NVARCAHR2),導致SQL走了全表掃描。
SQL類似如下:
SELECT * FROM T1,T2 WHERE T1.NAME=T2.NAME AND T1.NAME='XXX';
其中T1的NAME型別為:NVARCHAR2
T2的NAME型別為:VARCHAR2
[@more@]

這個SQL會發生隱式轉換(VARCHAR2 -> NVARCHAR2),所以,實際執行的SQL是:
SELECT * FROM T1,T2 WHERE T1.NAME=SYS_OP_C2C(T2.NAME) AND T1.NAME=U'XXX';
T2.NAME上多了一個函式,所以不能用到這列上的索引。

這個SQL,應該讓T1和T2都走索引,其實解決方法有兩種:
1、修改SQL
修改方法1:SELECT * FROM T1,T2 WHERE T1.NAME='XXX' AND T2.NAME='XXX';
修改方法2:SELECT * FROM T1,T2 WHERE T1.NAME='XXX' AND TO_CHAR(T1.NAME)=T2.NAME;

由於程式碼修改量大,且很難確保所有SQL都被修改,並且NVARCHAR2佔用的空間多,所以最好的辦法是修改表結構。

2、修改表結構
修改表結構需要聯機修改,否則會影響業務。
在聯機轉換NVARCHAR2到VARCHAR2時,有幾點需要注意:
1)新表的結構VARCHAR2的長度要足夠長,因為NVARCAHR2的長度定義的是字元個數,VARCHAR2定義的是位元組個數。在中文環境下把VARCHAR2的長度定義為NVARCHAR長度的2倍即可。
2)如果主鍵列也需要轉換,則重定義的時候options_flag要用ROWID,不能用主鍵
3)在匹配源表和新表欄位的對應關係時,對源表的列要使用函式轉換

舉一個例子如下:
drop table k1 purge;
drop table k2 purge;
create table k1(a nvarchar2(10) primary key,b nvarchar2(10),c nvarchar2(10));
create table k2(a varchar2(30) primary key,b varchar2(10),c varchar2(10));
insert into k1(a) values('abcsdfsdsa');
insert into k1(a) values('1234567890');
insert into k1(a) values('我是中國人收到測一下');
commit;
exec dbms_redefinition.can_redef_table('suk','k1');
exec DBMS_REDEFINITION.START_REDEF_TABLE('SUK','K1','K2','Translate(a USING CHAR_CS) a,Translate(b USING CHAR_CS) b,Translate(c USING CHAR_CS) c',dbms_redefinition.cons_use_rowid)
exec DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SUK','K1','K2')
exec dbms_redefinition.finish_redef_table('SUK','K1','K2')

--其中TRANSLATE ... USING 函式用於資料庫字符集和國家字符集之間轉換
--dbms_redefinition.cons_use_rowid用於指定轉換主鍵時的 option_flag為rowid

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/231499/viewspace-1013357/,如需轉載,請註明出處,否則將追究法律責任。

相關文章