Oracle字符集引發的幾個問題,常見的就是漢字佔多少個字節,其次就是字符集致使數據庫啓動失敗以及索引失效等問題html
漢字佔多少個字節?sql
select length('ABCDE中文字符串FG'),lengthb('ABCDE中文字符串FG') from dual;數據庫
就能夠知道,一個漢字佔了幾個字節,也能夠查看數據庫的字符集session
select * from nls_database_parameters where parameter ='NLS_CHARACTERSET';oracle
當NLS_CHARACTERSET=AL32UTF8時(UTF-8是變長編碼,每一個Unicode代碼點按照不一樣範圍,能夠有1-3字節的不一樣長度)
NLS_LENGTH_SEMANTICS=BYTE時,一個漢字表明三個字節
NLS_LENGTH_SEMANTICS=CHAR時,一個漢字表明一個字節
當NLS_CHARACTERSET=US7ASCII時(字符集爲單字節)
NLS_LENGTH_SEMANTICS=BYTE時,一個漢字表明兩個字節
NLS_LENGTH_SEMANTICS=CHAR時,一個漢字表明兩個字節函數
Oracle與漢字問題相關的函數工具
注意:計算長度的幾個方法區別以下:post
LENGTH(string1) 返回以字符爲單位的長度.
LENGTHB(string1) 返回以字節爲單位的長度.
LENGTHC(string1) 返回以Unicode徹底字符爲單位的長度.
LENGTH2(string1) 返回以UCS2代碼點爲單位的長度.
LENGTH4(string1) 返回以UCS4代碼點爲單位的長度.測試
substr,substrb均爲字符串截取函數,都帶有三個參數,第一個參數爲所要截取的字符串,第二個參數爲strart(索引均從1開始),第三個參數爲length。
substr是按照字來算的,而substrb()是按照字節來算的編碼
關於substr,substrb的例子舉例:
SQL> select substr('今天是個好日子',3,5) from dual;
----------
是個好日子
SQL> select substrb('今天是個好日子',3,5) from dual;
-----
天是
結論是substr是按照字來算的,而substrb()是按照字節來算的。看下面的例子:
SQL> select substr('abcdef',3,4) from dual;
----
cdef
SQL> select substrb('abcdef',3,4) from dual;
----
cdef
分析:對於字母來講,substr與substrb做用時同樣的,但對於漢字來講,substr是按字來取值,而substrb是按字節來取值,當所取長度爲奇數時,則自動捨棄最後一位字節。
相似的還有,
length與lengthb 長度計算函數
select length('你好') from dual ----output:2
select lengthb('你好') from dual ----output :4
Instr與Instrb 字符串查找函數 instr(原字符串,查的字符串,起始位置,第幾個匹配) 返回字符串位置,找不到返回0 .
select instr('日日花前長病酒','花前',1,1) from dual ----output:3
select instrb('日日花前長病酒','花前',1,1) from dual ----output:7
Oracle字符集
安裝數據庫的時候能夠設置字符集,不一樣版本可能默認的字符集是不同的(以Oracle 9i爲例子)
首先查看字符集:(注意:修改數據庫字符集時必須謹慎,修改以前必定要爲數據庫備份。因爲不能回退這項操做,所以可能會形成數據丟失或者損壞)
SQL> select name,value$ from props$ where name like '%NLS%'; NAME VALUE$ ------------------------------ ------------------------------ NLS_LANGUAGE AMERICAN NLS_TERRITORY AMERICA NLS_CURRENCY $ NLS_ISO_CURRENCY AMERICA NLS_NUMERIC_CHARACTERS ., NLS_CHARACTERSET US7ASCII NLS_CALENDAR GREGORIAN NLS_DATE_FORMAT DD-MON-RR NLS_DATE_LANGUAGE AMERICAN ………………. NLS_NCHAR_CHARACTERSET AL16UTF16 NLS_RDBMS_VERSION 9.2.0.4.0 20 rows selected. SQL> select name,dump(name) from eygle.test; NAME DUMP(NAME) ------------------------------------------------------ 測試 Typ=1 Len=4: 178,226,202,212 Test Typ=1 Len=4: 116,101,115,116 2 rows selected.
轉換字符集,你只能在新字符集是舊字符集嚴格超集的狀況下使用這種方式轉換。所謂超集是指:當前字符集中的每個字符在新字符集中均可以表示,並使用一樣的代碼點好比不少字符集都是US7ASCII的嚴格超集.
若是不是超集,將得到如下錯誤:
轉換字符集,數據庫應該在RESTRICTED模式下進行:
這時候,咱們能夠去查看alert<sid>.log日誌文件,看CLOB字段存在於哪些表上:
對於不一樣狀況,Oracle提供不一樣的解決方案,若是是用戶數據表,通常咱們能夠把包含CLOB字段的表導出,而後drop掉相關對象,
轉換後再導入數據庫;對於系統表,能夠按照如下方式處理:
在9.2.0中,轉換完成之後,能夠經過運行catmet.sql腳原本重建Metastylesheet表:
SQL> @?/rdbms/admin/catmet.sql
經過Metastylesheet表來測試不一樣字符集的影響。
提示:
經過設置sql_trace,咱們能夠跟蹤不少數據庫的後臺操做,這個工具是DBA經常使用的「利器」之一。
咱們簡單看一下數據庫更改字符集時的後臺處理,我提取了主要的更新部分。
經過如下跟蹤過程,咱們看到數據庫在更改字符集的時候,主要更新了12張數據字典表,修改了數據庫的原數據,這也證明了咱們之前的說法:
這個更改字符集的操做在本質上並不轉換任何數據庫字符,只是簡單的更新數據庫中全部跟字符集相關的信息。
注意:經過前面 」 ALTER DATABASE CHARACTER SET」 方式更改字符集時,Oracle至少須要更改12張數據字典表,而這種直接更新props$表的方式只完成了其中十二分之一的工做,潛在的完整性隱患是可 想而知的。並且經過更新props$表的方式修改字符集,在Oracle7以後就不該該被使用.