遷移ORACLE資料到MogDB/openGauss時的字符集問題
一、問題概述
ORACLE資料庫在儲存資料的時候,有時候會存在這樣一種現象,一張表裡的資料,既存在UTF8字元的,也存在GBK字元的,同時還有可能存在亂碼資料。
NLS_CHARACTERSET是資料庫字符集,NLS_NCHAR_CHARACTERSET是國家字符集,NLS_LANG 是 Oracle 資料庫客戶端的一個環境變數。
這種問題在於ORACLE對於規定了一種字符集後,對於插入的資料並沒有強校驗(garbage-in–garbage-out)。但是對於PG系的資料庫,資料庫的字符集在最開始建立資料庫的時候就指定了,而且一般情況下其中的表資料受字符集的嚴格校驗(SQL_ASCII除外)。
這也就導致了,原本是什麼型別的字元正常可以匯入到對應的字符集的庫裡,而原本直接存入ORACLE庫裡的和表原本的字符集不匹配的其他型別的字元可能無法轉換,此外亂碼資料可能直接不能轉換到PG系的庫裡。(ORACLE資料庫可以儲存亂碼資料,PG係資料庫有嚴格校驗)
一些常見場景如下:
1)如果恰巧資料庫的字符集也是UTF8, 那麼Oracle就不作任何轉換直接插入到資料中.
2)如果指定NLS_LANG是utf8, 但是輸入的卻是zhs16gbk的編碼, 那麼Oracle也會不作任何轉換, 將ZHS16GBK的字元編碼直接存入資料庫
3)如果資料庫的字元是AL32UTF8, 您指定NLS_LANG為ZHS16GBK, 但是, 您真正輸入的是UTF8的字元, 那麼,Oracle會把您輸入的UTF8字元當作ZHS16GBK字元轉換為UTF8存入資料庫. 這種情況會出現亂碼。
4)工具(putty/securecrt等等各種SSH客戶端等等)設定的字符集可能導致亂碼或者編碼轉換,客戶端字符集 NLS_LANG 和 個人工具顯示的字符集應該一致。
二、問題處理方案
1、使用SQL_ASCII字符集的資料庫
如果不考慮中文顯示以及亂碼顯示,可以直接在目標端建一個SQL_ASCII字符集的資料庫,那麼所有的資料均可以匯入到新的PG系的資料庫裡,這樣就不會有編碼轉換。這個設定基本不用來宣告所使用的編碼,因為此宣告會忽略編碼。在大多數情況下,如果使用了任何非ASCII資料,那麼我們不建議使用SQL_ASCII,因為openGauss/MogDB無法轉換或者校驗非ASCII字元。
2.根據原庫的編碼,建立相同字符集編碼的資料庫
ORACLE在建立資料庫的時候,需要指定字符集。雖然上述的一些原因導致ORACLE在指定了一種字符集的資料庫後,還可能存在其他型別的字元和亂碼資料,但這明顯是不符合規範的,因為拋開其他型別的資料,單單亂碼資料就不能算作有效資料,而且其他型別的資料,屬於違反了最初的規劃,也不能算作正常的資料。
因為不同的字元型別,對應儲存的不同的位元組長度是不一樣的,例如一個漢字,在UTF8裡儲存為3位位元組,而在GBK裡儲存為2個位元組。
比如一個“你”字,用UTF-8儲存在ORACLE資料裡,是佔用3個位元組,是“\xe4bda0”
而用GBK儲存在ORACLE資料裡,是佔用2個位元組,是“\xc4e3”
所以長度是不一致的,在它轉換到PG系的資料庫裡時,如果不能分辨出對應的是哪種型別的字元的話,只根據固定的一種型別的字符集的話,會存在部分資料的編碼無法轉換,在使用MTK(雲和恩墨的遷移工具)遷移資料的時候,可能類似於這種的報錯。
對於這種報錯,因為本身在原庫寫入的時候就存在問題,如果資料庫層大量修正的話,會耗費很大精力,因此,建議規範處理流程,僅根據資料庫的字符集遷移“正確”的資料,其餘的有問題的資料,可以在遷移過程找到對應的位置,或者進一步判斷出該類資料原本應該屬於什麼樣的字符集,然後這些問題資料讓應用自行修正。
(1)查詢儲存的編碼
在遇到問題資料的時候,我們可以根據其他正常的列,定位到對應的資料行,使用ORACLE的dump函式,檢視其在ORACLE資料庫裡儲存的編碼格式
select dump(sms_content,1016) code,sms_content from tab_xxx where mo_id=‘123123123132312’ CODE SMS_CONTENT -------------------------------------------------- ---------------------------------------------------------------------------------------------------- Typ=1 Len=64 CharacterSet=ZHS16GBK: 78,20,20,20,20 x :(; "“ ¥ ”€“" ,20,20,20,20,20,20,20,20,20,3a,28,a3,bb,20,20,20,2 0,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, 22,a1,b0,20,20,20,20,20,20,20,20,20,20,20,a3,a4,20 ,20,20,20,a1,b1,80,a1,b0,22
(2)根據函式或者工具檢驗出真實的字元編碼
然後可以把有問題的資料對應的編碼,根據不同位數進行轉換,看轉換的資料是否是正常可讀的資料,原本最開始查詢的資料不用額外關注,因為可能受本地終端字符集的影響,可能本身儲存的是正常的,例如,我查詢到了問題列的資料匯出的結果是如下。
取出部分編碼,進行轉換,"\xe59089e69e97"根據GBK按照兩位位元組的形式進行轉換,得到的是“鍚夋灄”,而根據UTF-8的型別進行轉換,得到的是“吉林”。因此原本這條資料本身應該是UTF-8的字符集。
可以使用相關函式進行轉換,也可以使用相關線上工具,例如:
postgres=# select convert_from(decode('e59089e69e97','hex')::bytea,'utf-8'); convert_from -------------- 吉林 (1 row)
而本身這條資料正確顯示的時候,應該為
根據此類方法,以及對業務資料的瞭解,可以分辨出原本資料應該屬於的字符集型別和非亂碼的資料。
(3)MTK遷移過程需要處理的部分
手動使用COPY處理
因為MTK遷移的過程可以指定每批次匯入資料的條數,在匯入資料存在此類字符集編碼問題的時候,我們一般會帶上igErrorData引數,會把有問題的整個批次的資料全部回滾,而其餘資料繼續入庫。
這個引數會在回滾那個問題批次資料的同時,把這個批次的資料記錄到錯誤檔案裡,產生csv檔案.
需要注意的是,這個csv是MTK分的遷移批次,每個批次的資料條數是一致的,可能在這一個批次裡,僅存在一條問題資料,但它會把整個批次的資料全部放到csv裡。可以先自行檢視csv篩出問題資料,或者定位問題資料。
這個時候,我們關注的是這個csv裡的正常資料,這個csv可以使用copy命令進行繞入。問題資料也可以暫時性先倒入,但是我們不關注因為字符集問題導致的查詢亂碼現象。
後續可以使用openGauss/MogDB的copy帶有的COMPATIBLE_ILLEGAL_CHARS引數,這個引數允許匯入非法字元容錯引數。此語法僅對COPY FROM匯入有效。但是在匯入這些存在問題的資料的時候,存在一個規則,即對於’\0’,容錯後轉換為空格,其他非法字元,容錯後轉換為問號。這部分資料即我們上文提到的屬於原庫就錯誤寫入的,後續應該讓業務修正。
MTK自動處理
MTK(v2.9.4)新增的compatibleIlLegaLChars選項決定了mogdb/openGauss使用MTK遷移過程裡,copy是否帶COMPATIBLE_ILLEGAL_CHARS選項。
如果開啟後,則會直接進行入上述的轉換方式,寫入資料,當然問題資料需要業務修正。(一般建議手動先產生錯誤的資料的csv後,定位有問題資料的位置後,再重新做一次自動處理的遷移)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69990629/viewspace-2993182/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MOGDB/openGauss與PostgreSQL關於GBK字符集問題SQL
- MOGDB/openGauss與PostgreSQL關於GDK字符集問題SQL
- Oracle使用RMAN從Windows遷移資料到LinuxOracleWindowsLinux
- openGauss/MogDB的uncommitted xmin問題解決MIT
- 遷移sqlserver資料到MongoDbSQLServerMongoDB
- django儲存資料到表時,遇到字符集問題--已解決Django
- mysqldump從mysql遷移資料到OceanBaseMySql
- 高速遷移MySQL資料到分散式時序資料庫DolphinDBMySql分散式資料庫
- 【Redis】redis遷移資料到redis-clusterRedis
- openGauss/MogDB的TPCH測試
- openGauss 反向全量遷移
- MogDB openGauss故障排查流程
- openGauss 反向遷移gs_replicate
- openGauss-反向全量遷移
- 自動化遷移七牛雲的資料到阿里雲OSS阿里
- 自動化遷移七牛雲的資料到阿里雲 OSS阿里
- 遷移資料庫資料考慮問題資料庫
- openGauss/MOGDB與PG等待事件事件
- 解決Oracle資料庫遷移後的伺服器負載效能問題JSOracle資料庫伺服器負載JS
- AWS RDS Oracle資料遷移Oracle
- MogDB/openGauss中merge的語法解析
- Oracle修改字符集前如何找出可能出現問題的資料?Oracle
- openGauss-反向遷移gs_replicate
- MogDB openGauss資料庫擴縮容的幾種方式資料庫
- 遷移Oracle資料庫時如何減小停機時間AAOracle資料庫
- 關於 Laravel 遷移遇到的問題Laravel
- 遷移學習中的BN問題遷移學習
- MogDB openGauss常用查詢彙總
- MogDB/openGauss如何實現事務的rollback
- openGauss資料庫分析問題資料庫
- 遷移Qt專案的路徑問題QT
- oracle遷移OCR盤Oracle
- Oracle遷移文件大全Oracle
- Oracle遷移文章大全Oracle
- fastdfs資料遷移以及fastdfs問題排查記錄AST
- MogDB-opengauss中的聚集與分組操作
- openGauss/MogDB列存表的delta表測試
- 無外網Oracle資料庫遷移Oracle資料庫