字符集問題的初步探討(七)-字符集更改的內部操作

noter發表於2007-07-04

字符集問題的初步探討(七)-字符集更改的內部操作

作者:eygle |
English Version版權宣告:轉載時請務必以超連結形式標明文章和作者資訊及本宣告
連結:

這部分並未包含於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沒有備份的操作中得到了慘痛的教訓。

 

 

相關文章