Oracle在資料轉儲時的字元集問題
作為一個Oracle資料庫的使用者,對於Export和Import兩個命令絕對不會感到陌生,因為這二者正是我們經常用於資料備份和恢複的工具。但在使用這兩個命令過程中所發生的Oracle字元集問題,常給一些Oracle使用者帶來不必要的麻煩和不必要的資料損失。本文將就Export和Import過程中Oracle字元集的轉換規律及使用這兩個命令的注意事項做一總結。
字元集轉換的原因
Export、Import過程如所示,從這個中可以看到有四處關係到字元集,而這四處字元集的不一致恰恰是導致Oracle進行字元集轉換的原因。
來源資料庫字元集;
Export過程中使用者會話字元集;
Import過程中使用者會話字元集;
目標資料庫字元集。
在Export和Import過程中,如果存在影響字元集轉換的四因素不一致,則可能發生Oracle字元集轉換,即:
在Export過程中,如果來源資料庫字元集與Export使用者會話字元集不一致,會發生字元集轉換,並在匯出的二進位格式Dmp檔案的頭部幾個位元組中儲存Export使用者會話字元集的ID號。在這個轉換過程中可能發生資料的丟失。
例1: 如果來源資料庫使用ZHS16GBK,而Export使用者會話字元集使用US7ASCII,由於ZHS16GBK是8位字元集,而US7ASCII是7位字元集,這個轉換過程中,中文字元在US7ASCII中不能夠找到對等的字元,所以所有中文字元都會丟失而變成“?? ”形式,即這種轉換後產生的Dmp檔案已經發生了資料丟失。
例2: 如果來源資料庫使用ZHS16GBK,而Export使用者會話字元集使用ZHS16CGB231280,但由於ZHS16GBK字元集是ZHS16CGB231280字元集的超集,這個過程中絕大部分字元都能夠正確轉換,只有一些超出ZHS16CGB231280字元集的字元變為“?? ”形式。如果來源資料庫使用ZHS16CGB231280字元集,而Export使用者會話使用ZHS16GBK字元集,則轉換過程能夠完全轉換成功。
在Import向目標資料庫轉換過程中,其字元集發生轉換的情況正好與Export過程相反,這裡不再詳述。
在Export匯出的Dmp檔案中,含有Export使用者會話字元集。在Import過程中,首先發生的是Dmp檔案字元集(即Export使用者會話字元集)向Import使用者會話字元集的轉換。如果這個轉換過程不能正確完成,Import向目標資料庫的匯入處理程序也就不能完成。
進行字元集的正確轉換
通常情況下,我們在使用Oracle的Export和Import過程中,並不希望發生字元的轉換,但有時這種轉換卻是必要的。如我們在安裝Oracle資料庫時,選擇ZHS16CGB231280字元集,由於這種字元集是一種中文小字元集,對於一些漢字不能夠正確表示,這需要通過使用ZHS16GBK字元集得到解決,此時就要進行字元集的轉換。
為了確保Export、Import過程中,Oracle字元集不發生轉換或正確轉換,建議最好在進行這個過程前,檢查一下來源資料庫字元集與Export使用者會話字元集是否一致,來源資料庫字元集與目標資料庫字元集是否一致,目標資料庫字元與Import使用者會話字元集是否一致。如果能夠保證這四個字元集是一致的,則在Export、Import過程中,Oracle字元集就不用發生轉換。
可用以下辦法檢查資料庫字元集:
通過InitXXXX.ora檔案進行查看;
藉助SQL語句查看: SELECT NAME,VALUE$ FROM SYS.PROPS$ WHERE NAME=‘NLS_CHARACTERSET’。
對於Export、Import使用者會話字元集,在Windows系統中也可以通過註冊表中的NLS_LANG進行查看或修改,對於Unix系統則可通過設定使用者的環境變數NLS_LANG來查看或修改。
特別要注意的是,Oracle資料庫字元集通常是在建立時確定,一旦儲存使用者資料後就不要再修改了,因為其資料都是使用該字元集進行儲存的,改換其他字元集之後,原有資料就不能夠正確表示了。但如果確實想進行字元集改變,則可通過以下幾步來實現:
備份資料庫後刪除原資料(可物理備份,如使用Export,請注意確保字元集不發生轉換或資料無損失);
使用Internal使用者更新sys.props$表中的字元集:
Update sys.props$ set name=‘Dest.CharSet’ Where name=‘NLS_CHARACTERSET’; COMMIT;
重啟資料庫;
恢複資料。
下面字元集之間的轉換是可行的:
字元集子集向字元集父集轉換是可行的,如ZHS16CGB231280向ZHS16GBK轉換;而字元集父類向字元集子集進行轉換時,會損失部分資料。
只包含英文字元資料的雙位元組字元集也可向單一位元組字元集轉換,如ZHS16GBK(English Only)可以向US7ASCII正確轉換。
編碼範圍相同的單一位元組字元集之間通常可以進行相互轉換。
請注意,這裡所說的沒有資料損失,是指一種字元集A轉換成另一種字元集B之後,可以再從字元集B正確轉換成字元集A或字元集B能夠正確表示字元集A中轉換過來的資料。
字元集對程式的影響
根據一個字元需要多少位位元組來表示,可以把字元集分為單一位元組字元集和多位元組字元集。其中,單一位元組字元集又分為7位字元集和8位字元集。單位元組7位編碼字元集有US7ASCⅡ,單位元組8位編碼字元集有符合ISO 8859-1標準規定的WE8ISO8859P1等。多位元組編碼又分為固定長度(長度大於或等於2)編碼模式和不固定長度編碼模式。多位元組編碼字元集中的ZHS16GBK、ZHS16CGB231280、JA16SJIS等是採用兩個位元組表示一個字元的字元集,又叫雙位元組字元集。
一個英文字母是一個字元,一個中文漢字是幾個字元呢?我們知道,一個中文漢字是雙位元組字元,但它有幾個字元與其資料庫字元集有關。如果資料庫字元集使用單位元組US7ASCII,則一個中文漢字是二個字元;如果資料庫字元集使用雙位元組字元集ZHS16GBK,則一個中文漢字是一個字元。有關這一點可以使用Oracle的函數Substr得到證明。
使用US7ASCⅡ字元集時:
Select substr(‘東北大學’,1,2) from dual;
語句執行結果返回‘東’。
使用ZHS16GBK字元集時:
Select substr(‘東北大學’,1,2) from dual;
語句執行結果返回‘東北’。
選擇合適的資料庫字元集
選擇資料庫字元集時應考慮以下事項:
1.資料庫需要支援什麼語言
在為資料庫選擇字元集時,常會發現幾種字元集都適合你當前語言需求,如簡體中文就有ZHS16GBK和ZHSCGB231280等字元集可供選擇,應選擇哪種?在選擇字元集時,應考慮到資料庫將來的系統需求。如果知道將來資料庫要擴充支援不同的語言,選擇一個範圍較廣的字元集會是一個更好的主意。
2.系統資源與應用之間的互作用性
選擇的資料庫字元集應保證作業系統與應用之間的無縫串連。如果選擇的字元集不是作業系統有效字元集,則系統就需要在這兩者之間做字元轉換。在這種字元轉換過程中,就有可能發生一些字元丟失現象。從一種字元集A向另一種字元集B轉換過程中,A中的字元必須在B中可以找到等價的字元,否則就會以“?”來代替。從這個意義上說,如果兩種字元集編碼範圍是相同的,則可以相互轉換。
字元集轉換過程中會影響系統效能,因此,應保證用戶端和伺服器端有相同的字元集以避免字元集轉換,也可以提高一定的系統效能。
3.系統的效能要求
不同的資料庫字元集對於資料庫的效能是有一定影響的。為了得到最好的資料庫效能,選擇的資料庫字元集應避免字元轉換,並且要選擇對於期望的語言有最高效的編碼效率。通常,單一位元組字元集比多位元組字元集有更優的效能表現,在空間需求方面也更小些。
4.其他一些限制
在為資料庫選擇一個合適的字元集時,應參考Oracle對應版本的相關文檔,檢查Oracle對於一些字元集的限制。如Oracle 8.1.5版本中,以下字元集是不能使用的: JA16EUCFIXED、ZHS16GBKFIXED、JA16DBCSFIXED、KO16DBCSFIXED、ZHS16DBCSFIXED、JA16SJISFIXED、ZHT32TRISFIXED。