糾正要求修改資料庫NLS_LENGTH_SEMANTICS參數的錯誤要求,nlslengthsemantics

來源:互聯網
上載者:User

糾正要求修改資料庫NLS_LENGTH_SEMANTICS參數的錯誤要求,nlslengthsemantics
1、開發人員錯誤的要求

      先看一封開發人員向某DBA提出的一個“要求修改資料庫NLS_LENGTH_SEMANTICS參數並重啟資料庫”的郵件:

   

    上面郵件,出於對隱私的保護,對寄件者,收件者,資料庫名稱進行了隱塗。

郵件內容主要意思是:

    (1)   源端和目標端資料庫的字元集均為SIMPLIFIED CHINESE_CHINA.UTF8,但是源端資料庫NLS_LENGTH_SEMANTICS參數的值為char,目標資料庫NLS_LENGTH_SEMANTICS參數的值為byte

    (2)   郵件中對知識錯誤的理解:由於源端資料庫NLS_LENGTH_SEMANTICS參數的值為char(把1個漢字當成一個位元組),目標資料庫NLS_LENGTH_SEMANTICS參數的值為byte(把1個漢字佔3個位元組),所以,源端Varchar2(16)能儲存16個漢字,而目標端Varchar2(16)即只能存5個漢字,導致來源資料的資料無法插入到目標端資料庫中去

    (3)   郵件中錯誤的建議解決辦法:將目標端資料庫的NLS_LENGTH_SEMANTICS參數的值,改成與源端資料庫NLS_LENGTH_SEMANTICS參數相同的值

2、知識的梳理2.1 NLS_LENGTH_SEMANTICS參數的用途

        NLS_LENGTH_SEMANTICS參數是一個專為建立CHAR和VARCHAR2兩種字元型的列時,指定使用的位元組長度,還是使用字元長度的定義方式,有byte和char兩種值,預設為byte。

        當設定該參數為BYTE時,定義CHAR列或VARCHAR2列採用位元組長度方式;當設定該參數為CHAR時,定義CHAR列或VARCHAR2列採用字元長度的方式。該參數對於資料庫中已經存在的列不具備任何用途,只是在建立表,或修改表的列時才具有意義。

2.2 位元組長度與字元長度的區別

     此章節從百度文庫摘抄,原文地址為:http://baike.baidu.com/link?url=gtnaOI4rLZejxtdNISG3z8Vm1IpobqAB4nv3TRSnKh9RwTo2eR8eRkUWUUv00J7INVvGPQ2O51o-r77SfyIwT_

(1)ASCII碼:

      一個英文字母(不分大小寫)佔一個位元組的空間,一個中文漢字佔兩個位元組的空間。一個位元字序列,在電腦中作為一個數字單元,一般為8位位元,換算為十進位。最小值0,最大值255。如一個ASCII碼就是一個位元組。

(2)UTF-8編碼:

      一個英文字元等於一個位元組,一個中文(含繁體)等於三個位元組。

(3)   Unicode編碼:

      一個英文等於兩個位元組,一個中文(含繁體)等於兩個位元組。

(4)   符號:

      一個英文標點佔一個位元組,一個中文標點佔兩個位元組。舉例:英文句號“.”佔1個位元組的大小,中文句號“。”佔2個位元組的大小。

3、郵件中對知識錯誤的理解

        郵件中要求修改目標端資料庫NLS_LENGTH_SEMANTICS參數,是完全錯誤的解決方案,之所以出現這樣的情況,是因為此開發人員對NLS_LENGTH_SEMANTICS參數的理解不正確。

        該開發人員,錯誤的將NLS_LENGTH_SEMANTICS參數理解成,只要該參數一改,資料庫中所有的涉及CHAR和VARCHAR2兩種字元型的列的長度類型都發生變化了。

        其實不是,NLS_LENGTH_SEMANTICS參數的值,不對已經存在的列產生任何影響,只是在建立表中的列時,預設的指定列長度類型為byte還是char,如果在建立或修改表的列時指定了長度類型,完全覆蓋NLS_LENGTH_SEMANTICS參數的值。

4、剖析問題的真正原因

        其實,該開發人員所面對的真正問題原因,是源端表欄位的長度類型與目標端表欄位長度的類型不一致所致。

        問題根本原因搞清楚了,解決方案就容易了,將目標端表的欄位長度類型修改成與源端一樣,不就解決了木。何必修改資料庫參數還重啟資料庫的。

        下面以三條create table的語句說清楚NLS_LENGTH_SEMANTICS參數的用途

(1)兩條指定長度類型的SQL語句

create table tab_t(t_name varchar2(20byte));

create table tab_t(t_name varchar2(20char));

        上面兩條語句,唯一的不同,就是在指定列長度為20後,再指定長度的類型,類型的值不同。

(2)不指定長度類型的SQL語句

create table tab_t(t_name varchar2(20));

        這條語句,在指定列的長度為20後,並未指定長度的類型,那它的類型會是什麼呢,這個就是由NLS_LENGTH_SEMANTICS參數的值所決定了,該參數值可以在會話級設定。

5、測實驗證5.1 確認資料庫的字元集類型

SQL> select *from nls_database_parameters t where t.parameter='NLS_CHARACTERSET';

PARAMETER                      VALUE

------------------------------   --------------------------------------

NLS_CHARACTERSET               AL32UTF8

 

5.2 建立列長度類型為byte的表並測試可插入資料長度

(1)查看NLS_LENGTH_SEMANTICS參數當前值

SQL> selectname,value from v$parameter where upper(name)='NLS_LENGTH_SEMANTICS';

NAME                 VALUE

------------------------------   -------------------------------

nls_length_semantics     BYTE

 

(2)建立帶列長度類型為byte的表

SQL>create table tab_t(t_name varchar2(3));

(3)查看新建立的tab_t表的t_name列長度類型

SQL>select table_name,column_name,data_type,char_usedfrom dba_tab_columnswhere table_name='TAB_T'

TABLE_NAME    COLUMN_NAME      DATA_TYPE     CHAR_USED                                                                    

--------------------  -----------------------    -------------------------  -----------------------------

TAB_T                   T_NAME                    VARCHAR2        B

(4)插入英文字串資料測試

$ export NLS_LANG=AMERICAN_AMERICA.UTF8

--注意上面這一條,設定用戶端字元集很重要,如果環境變數有設定,此步可以跳過。如果發生複雜的字元集轉換,一個中文漢字有可能會佔用6個位元組

 

SQL> insert into tab_t values ('ZHO');

 1 row created.

 

SQL> insert into tab_t values ('ZHON');

insert into tab_t values ('ZHON')

                          *

ERROR at line 1:

ORA-12899: value too large for column "SYS"."TAB_T"."T_NAME" (actual: 4,maximum: 3)

從上面測試資料來看,插入三個英文字母成功,在插入四個字母的字串時失敗,提示實際長度為4,但maximum只有3

(5)   插入中文字串資料測試

1)先計劃一下“中”字佔用幾個位元組

 SQL> SELECT  LENGTHB('中') FROM DUAL;

LENGTHB('中')

-------------

            3

2)插入一個中文漢字

SQL> insert into tab_t values ('中');

1 row created.

 

3)插入兩個中文漢字

SQL> insert into tab_t values ('中國');

insert into tab_t values ('中國')

                          *

ERROR at line 1:

ORA-12899: value too large for column "SYS"."TAB_T"."T_NAME" (actual: 6, maximum: 3)

插入兩個中文漢字失敗,實際長度為6,欄位maximum只有3,在此驗證確定,在UTF8下,一個中文漢字佔3個字元。

 

5.3 將tab_t表的t_name列更改成char長度類型並做可插入長度測試

(1)將tab_t表的t_name列長度類型更改成char

SQL>alter table tab_t modify (t_name varchar2(3char));

(2)驗證修改結果

SQL> selecttable_name,column_name,data_type,char_used from dba_tab_columns wheretable_name='TAB_T' ;

TABLE_NAME    COLUMN_NAME      DATA_TYPE     CHAR_USED                                                                    

--------------------  -----------------------    -------------------------  -----------------------------

TAB_T                    T_NAME                   VARCHAR2        C

(3)   插入兩個中文漢字

SQL> insert into tab_t values ('中國');

 

1 row created.

 varchar2(3 char)插入兩個中文漢字成功

 

6、小結

        經過對開發人員的需求進行判斷,以及糾正其對NLS_LENGTH_SEMANTICS參數用途錯誤的理解,用修改表欄位長度類型的方式解決其面臨的實際問題,避免了一次不必要的資料庫重啟,以及問題得到真正的解決。

 

 

本文作者:黎俊傑(網名:踩點),從事”系統架構、作業系統、存放裝置、資料庫、中介軟體、應用程式“六個層面系統性的效能最佳化工作

歡迎加入系統效能最佳化專業群,共同探討效能最佳化技術。群號:258187244

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.