聊聊字串資料長度和nls_length_semantics引數
字串是我們設計資料庫經常用到的型別,從傳統的ASCII格式到UTF-8格式,不同應用需求對應不同的字元型別和長度配置。針對Oracle而言,最常用的型別無外乎char和varchar2兩個基本型別。
對於一些中文應用,設計人員就需要重點關注資料表中字串長度問題。因為在不同的字串編碼方式下,一箇中文字元對應的字元byte長度是不同的。比如,一個欄位長度設定為10,如果是英文字元就可以容納10位長度,如果是中文字元就只能容納最多5位長度。如果採用如UTF-8類寬泛字符集型別,也就3-4箇中文字元。
字串型別的長度定義,這個含義是什麼?在Oracle中,我們定義varchar2(10)其實是有兩層理解,一則是10個byte位長度,另一則是10個輸入字元長度。兩種理解前者是技術派,後者理解是從業務應用角度看問題。其實,在Oracle實現層面,兩種策略都是支援的。本篇主要說明一下字串長度問題,供日後待查。
1、環境說明
筆者選擇Oracle 11gR2版本進行測試實驗,具體版本號為11.2.0.4。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE 11.2.0.4.0 Production
TNS for 64-bit Windows: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 – Production
當前字符集為AL32UTF8。
SQL> select * from nls_database_parameters where parameter='NLS_CHARACTERSET';
PARAMETER VALUE
------------------------------ ---------------
NLS_CHARACTERSET AL32UTF8
2、預設引數設定
首先實驗一下預設條件下,Oracle字串行為方式。建立實驗表t。
SQL> create table t (v_char varchar2(10));
Table created
SQL> desc t;
Name Type Nullable Default Comments
------ ------------ -------- ------- --------
V_CHAR VARCHAR2(10) Y
SQL> insert into t values ('ttt');
1 row inserted
SQL> insert into t values ('tttttttttt');
1 row inserted
SQL> commit;
Commit complete
預設情況下,對於varchar2(10)型別,英文字元可以容納下10個字元。下面測試中文字元情況。
SQL> insert into t values ('保護');
1 row inserted
SQL> commit;
Commit complete
SQL> insert into t values ('保護模式');
insert into t values ('保護模式')
ORA-12899: 列 "TEST"."T"."V_CHAR" 的值太大 (實際值: 12, 最大值: 10)
SQL> insert into t values ('保護模');
1 row inserted
SQL> commit;
Commit complete
對於長度varchar2(10)的欄位型別,三位中文似乎是一個上限。從四位中文輸入報錯的情況看,當前資料庫將一箇中文識別為三個長度進行計量。潛含的意思是在UTF-8編碼情況下,varchar2(10)表示的是10位byte長度。
那麼,控制長度單位是引數是什麼呢?
3、Char & Byte
從Oracle語法上看,varchar2(10)這個10後面其實是包括單位的。預設情況下,我們都不需要去管理這個配置。如果我們不顯示的進行指定,Oracle會取自引數nls_length_semantics。
SQL> show parameter nls_length
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_length_semantics string BYTE
在建立資料表和定義欄位過程中,我們是可以明確指定長度單位的。Oracle提供了兩種選擇,一個是byte,另一個是char型別。
SQL> create table t_char (v_char varchar2(10 char), v_byte varchar2(10));
Table created
SQL> desc t_char;
Name Type Nullable Default Comments
------ ----------------- -------- ------- --------
V_CHAR VARCHAR2(10 CHAR) Y
V_BYTE VARCHAR2(10) Y
當前是byte預設單位模式下(注意這個前提),v_char欄位明顯顯示10位字元長度。
SQL> insert into t_char(v_char) values ('tttttttttt');
1 row inserted
SQL> insert into t_char(v_char) values ('ttttttttttt');
insert into t_char(v_char) values ('ttttttttttt')
ORA-12899: 列 "TEST"."T_CHAR"."V_CHAR" 的值太大 (實際值: 11, 最大值: 10)
SQL> commit;
Commit complete
10位英文字元測試透過,下面試驗一下中文字元。
SQL> insert into t_char(v_char) values ('實驗實驗實驗實驗實驗');
1 row inserted
SQL> commit;
Commit complete
SQL> insert into t_char(v_char) values ('實驗實驗實驗實驗實驗實驗');
insert into t_char(v_char) values ('實驗實驗實驗實驗實驗實驗')
ORA-12899: 列 "TEST"."T_CHAR"."V_CHAR" 的值太大 (實際值: 12, 最大值: 10)
SQL> select * from t_char;
V_CHAR V_BYTE
---------------------------------------- ----------
tttttttttt
實驗實驗實驗實驗實驗
十個中文字元可以容納,使用dump檢視儲存結構編碼。
SQL> select dump(v_char, 1016) as a from t_char;
A
------------------------------------------------------------------------------------------------------------------------------
Typ=1 Len=10 CharacterSet=AL32UTF8: 74,74,74,74,74,74,74,74,74,74
Typ=1 Len=30 CharacterSet=AL32UTF8: e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c,e5,ae,9e,e9,aa,8c
說明:在char計量單位下,資料庫不會按照儲存技術結構進行長度選取,而是根據實際存放長度進行計量。
那麼,預設情況下的取值,與顯示進行byte相對應。
SQL> create table t_byte (v_char varchar2(10 byte));
Table created
SQL> desc t_byte;
Name Type Nullable Default Comments
------ ------------ -------- ------- --------
V_CHAR VARCHAR2(10) Y
4、引數變更實驗
如果進行引數變化,資料庫行為是如何呢?
SQL> conn sys/oracle@sicsdb as sysdba
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0
Connected as SYS
SQL> show parameter nls_leng
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_length_semantics string BYTE
修改引數取值。
SQL> alter system set nls_length_semantics=char scope=both;
System altered
SQL> show parameter nls_leng
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_length_semantics string CHAR
注意,此時已經修改了引數,進行實驗。
SQL> create table t_test (v_char varchar2(10));
Table created
SQL> desc t_test;
Name Type Nullable Default Comments
------ ------------ -------- ------- --------
V_CHAR VARCHAR2(10) Y
SQL> insert into t_test values ('實驗實驗實驗');
insert into t_test values ('實驗實驗實驗')
ORA-12899: 列 "TEST"."T_TEST"."V_CHAR" 的值太大 (實際值: 18, 最大值: 10)
長度配置預設單位沒有變化。依然是byte的效果。如果需要引數生效,需要重新啟動資料庫例項。
SQL> startup force
ORACLE instance started.
Total System Global Area 4275781632 bytes
Fixed Size 2288080 bytes
Variable Size 939525680 bytes
Database Buffers 3321888768 bytes
Redo Buffers 12079104 bytes
Database mounted.
Database opened.
SQL> show parameter nls_leng
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_length_semantics string CHAR
此時檢視預設建立行為。
SQL> conn test/test@sicsdb
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0
Connected as test
SQL> create table t_test (v_char varchar2(10));
Table created
SQL> desc t_test
Name Type Nullable Default Comments
------ ------------ -------- ------- --------
V_CHAR VARCHAR2(10) Y
SQL> insert into t_test values ('實驗實驗實驗實驗實驗');
1 row inserted
SQL> commit;
Commit complete
SQL> select * from t_test;
V_CHAR
----------------------------------------
實驗實驗實驗實驗實驗
同時,過去定義為byte計量的單元欄位也被明顯顯示出來。
SQL> desc t_char
Name Type Nullable Default Comments
------ ----------------- -------- ------- --------
V_CHAR VARCHAR2(10) Y
V_BYTE VARCHAR2(10 BYTE) Y
SQL> desc t_byte
Name Type Nullable Default Comments
------ ----------------- -------- ------- --------
V_CHAR VARCHAR2(10 BYTE) Y
5、結論
資料庫欄位長度在傳統的應用開發領域是一個比較重要的問題。傳統觀點認為這部分應該體現業務邏輯思想,也就是將欄位的長度與業務邏輯對應,甚至可以透過資料庫來控制使用者操作。但是,由於字串長度因素、軟體設計思想的變化影響,這部分邏輯越來越被推到了介面和應用邏輯層次來完成。
對Oracle而言,提供char方式定義欄位是一種備選的策略。在確實需要資料庫嚴格反應業務邏輯的情況下,是一種不錯的選擇。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2084683/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 取字串長度字串
- php函式之如何用預設引數和可變長度引數方式傳遞?PHP函式
- shell 怎麼獲取引數的長度
- JavaScript生成指定長度的數字與字母字串JavaScript字串
- ABAP字串操作 擷取字元長度 取位數字串字元
- 字串的長度,是字元數量,還是位元組數量?字串字元
- shell獲取字串長度字串
- oracle 獲取字串長度函式length()和lengthb()Oracle字串函式
- oracle取字串長度的函式length()和hengthb()Oracle字串函式
- 擷取指定長度字串長度程式碼例項字串
- Laravel同時接收路由引數和查詢字串中的引數Laravel路由字串
- 聊聊jdk httpclient的retry引數JDKHTTPclient
- 取字串左邊指定長度的子字串字串
- 取字串右邊指定長度的子字串字串
- js獲取字串長度區分漢字和英文JS字串
- golang 計算最長不重複字串長度Golang字串
- 資料型別及長度資料型別
- TCP傳輸資料長度TCP
- Java 陣列的不同定義方式和陣列長度為可變引數Java陣列
- 如何擷取指定長度字串區分漢字和字元字串字元
- 表單限制字串輸入長度字串
- JavaScript計算字串位元組長度JavaScript字串
- c#基礎-5.變長引數和引數預設值C#
- 資料庫系列:字首索引和索引長度的取捨資料庫索引
- 求字串中對稱的子字串的最大長度字串
- MySQL資料庫引數MySql資料庫
- oracle 資料泵引數Oracle
- Java不定長引數Java
- 按位長度進行字串的分割輸出,長度不足補0字串
- subprocess中命令為引數序列和字串的區別字串
- String字串的最大長度是多少?字串
- 求給定字串的平均字元長度字串字元
- 第七章——字串(不定長度字元)字串字元
- QT生成固定長度的隨機字串QT隨機字串
- kettle 引數——變數引數和常量引數變數
- 資料線線損和長度對資料傳輸和網路傳輸的影響
- Exp和資料泵(Data Pump)的query引數使用
- pytest的資料驅動和引數傳遞