字符集問題的初步探討(七)-字符集更改的內部操作
作者:
eygle |
English Version 【
版權宣告:轉載時請務必以超連結形式標明文章
原始出處和作者資訊及
本宣告】
連結:
http://www.eygle.com/archives/2004/09/nls_character_set_07.html這部分並未包含於itpub技術叢書《Oracle資料庫DBA專題技術精粹》中,是後來補充的內容.
前面我們提到,通過修改props$的方式更改字符集在Oracle7之後是一種極其危險的方式,應該儘量避免。
我們又知道,通過ALTER DATABASE CHARACTER SET更改字符集雖然安全可靠,但是有嚴格的子集和超集的約束,實際上我們很少能夠
用到這種方法。
實際上Oracle還存在另外一種更改字符集的方式.
如果你注意過的話,在Oracle的alert<sid>.log檔案中,你可能看到過這樣的日誌資訊:
alter database character set INTERNAL_CONVERT ZHS16GBK Updating character set in controlfile to ZHS16GBK SYS.SNAP$ (REL_QUERY) - CLOB representation altered SYS.METASTYLESHEET (STYLESHEET) - CLOB representation altered SYS.EXTERNAL_TAB$ (PARAM_CLOB) - CLOB representation altered XDB.XDB$RESOURCE (SYS_NC00027$) - CLOB representation altered ODM.ODM_PMML_DTD (DTD) - CLOB representation altered OE.WAREHOUSES (SYS_NC00003$) - CLOB representation altered PM.ONLINE_MEDIA (SYS_NC00042$) - CLOB representation altered PM.ONLINE_MEDIA (SYS_NC00062$) - CLOB representation altered PM.ONLINE_MEDIA (PRODUCT_TEXT) - CLOB representation altered PM.ONLINE_MEDIA (SYS_NC00080$) - CLOB representation altered PM.PRINT_MEDIA (AD_SOURCETEXT) - CLOB representation altered PM.PRINT_MEDIA (AD_FINALTEXT) - CLOB representation altered Completed: alter database character set INTERNAL_CONVERT ZHS1
|
在這裡面,我們看到這樣一條重要的,Oracle非公開的命令:
這個命令是當你選擇了使用典型方式建立了種子資料庫以後,Oracle會根據你選擇的字符集設定,把當前種子資料庫的字符集更改為期望字元
集,這就是這條命令的作用.
在使用這個命令時,Oracle會跳過所有子集及超集的檢查,在任意字符集之間進行強制轉換,所以,使用這個命令時你必須十分小心,你必須
清楚這一操作會帶來的風險.
我們之前講過的內容仍然有效,你可以使用csscan掃描整個資料庫,如果在轉換的字符集之間確認沒有嚴重的資料損壞,或者你可以使用有效
的方式更改,你就可以使用這種方式進行轉換.
我們來看一下具體的操作過程及Oracle的內部操作:
SQL> shutdown immediate Database closed. Database dismounted. ORACLE instance shut down. SQL> startup mount ORACLE instance started.
Total System Global Area 135337420 bytes Fixed Size 452044 bytes Variable Size 109051904 bytes Database Buffers 25165824 bytes Redo Buffers 667648 bytes Database mounted.
SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;
System altered.
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
System altered.
SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;
System altered.
SQL> ALTER DATABASE OPEN;
Database altered.
SQL> alter session set events '10046 trace name context forever,level 12';
Session altered.
SQL> alter database character set INTERNAL_USE ZHS16CGB231280
Database altered.
SQL>
|
這是alert.log檔案中的記錄資訊:
格式化10046跟蹤檔案,得到以下資訊(摘要):
alter session set events '10046 trace name context forever,level 12'
alter database character set INTERNAL_USE ZHS16CGB231280
call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 4.88 6.04 910 16825 18099 0 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 2 4.88 6.04 910 16825 18099 0
Misses in library cache during parse: 1 Optimizer goal: CHOOSE Parsing user id: SYS
Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ control file sequential read 4 0.00 0.00 control file parallel write 2 0.05 0.08 log file sync 2 0.08 0.08 SQL*Net message to client 1 0.00 0.00 SQL*Net message from client 1 18.06 18.06 ********************************************************************************
....
update col$ set charsetid = :1 where charsetform = :2
....
update argument$ set charsetid = :1 where charsetform = :2
....
update collection$ set charsetid = :1 where charsetform = :2
....
update attribute$ set charsetid = :1 where charsetform = :2 ....
update parameter$ set charsetid = :1 where charsetform = :2 ....
update result$ set charsetid = :1 where charsetform = :2
....
update partcol$ set spare1 = :1 where charsetform = :2
....
update subpartcol$ set spare1 = :1 where charsetform = :2
....
update props$ set value$ = :1 where name = :2
....
update "SYS"."KOTAD___FCKpd___4quot; set SYS_NC_ROWINFO$ = :1 where SYS_NC_OID$ = :2 ....
update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6, cache=:7,highwater=:8,audit$=:9,flags=:10 where obj#=:1
....
update kopm$ set metadata = :1, length = :2 where name='DB_FDO'
....
ALTER DATABASE CLOSE NORMAL
|
此處生成的日誌你可以在這裡下載(供參考):
http://www.eygle.com/special/primary_ora_13730.zip
http://www.eygle.com/special/primary_ora_13730.tkf.log
我們看到這個過程和之前ALTER DATABASE CHARACTER SET操作的內部過程是完全相同的,也就是說INTERNAL_USE提供的幫助就是使
Oracle資料庫繞過了子集與超集的校驗.
這一方法在某些方面是有用處的,比如測試;應用於產品環境大家應該格外小心,除了你以外,沒有人會為此帶來的後果負責:
結語(我們不妨再說一次):
對於DBA來說,有一個很重要的原則就是:不要把你的資料庫置於危險的境地!
這就要求我們,在進行任何可能對資料庫結構發生改變的操作之前,先做有效的備份,很多DBA沒有備份的操作中得到了慘痛的教訓。