ITPub博客

首页 > 数据库 > Oracle > [20250729]绑定变量的字符串长度与字符集相关问题.txt

[20250729]绑定变量的字符串长度与字符集相关问题.txt

原创 Oracle 作者:lfree 时间:2025-07-31 20:48:16 0 删除 编辑

[20250729]绑定变量的字符串长度与字符集相关问题.txt

--//前段时间别人遇到的问题当时猜测与字符集相关,我记忆里https://nenadnoveljic.com/blog/bind_variable_length/有一个演示,
--//当时在我的测试环境就没有测试出来,当时猜测对方使用的字符集与我的不同。

--//在自己的测试环境重复测试看看,加强理解:

1.环境改造:
--//先修改环境变量LANG=en_US.UTF-8。
# cat /etc/locale.conf
LANG="en_US.UTF-8"
#LANG="en_US"

2.使用putty或者kitty登录。
--//配置在window->translation,remote character set 选择UTF-8.
--//登录简单的检查在bash shell的提示输入中文看看是否显示正常。

3.启动数据库略。
--//启动前修改环境变量
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
--//重新登录oracle,启动数据库略。

SYS@book> select * from v$nls_parameters ;
PARAMETER                      VALUE                                CON_ID
------------------------------ -------------------------------- ----------
NLS_LANGUAGE                   AMERICAN                                  1
NLS_TERRITORY                  AMERICA                                   1
NLS_CURRENCY                   $                                         1
NLS_ISO_CURRENCY               AMERICA                                   1
NLS_NUMERIC_CHARACTERS         .,                                        1
NLS_CALENDAR                   GREGORIAN                                 1
NLS_DATE_FORMAT                YYYY-MM-DD HH24:MI:SS                     1
NLS_DATE_LANGUAGE              AMERICAN                                  1
NLS_CHARACTERSET               ZHS16GBK                                  1
NLS_SORT                       BINARY                                    1
NLS_TIME_FORMAT                HH.MI.SSXFF AM                            1
NLS_TIMESTAMP_FORMAT           YYYY-MM-DD HH24:MI:SS.FF                  1
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR                        1
NLS_TIMESTAMP_TZ_FORMAT        YYYY-MM-DD HH24:MI:SS.FF TZH:TZM          1
NLS_DUAL_CURRENCY              $                                         1
NLS_NCHAR_CHARACTERSET         AL16UTF16                                 1
NLS_COMP                       BINARY                                    1
NLS_LENGTH_SEMANTICS           BYTE                                      1
NLS_NCHAR_CONV_EXCP            FALSE                                     1
19 rows selected.
--//NLS_NCHAR_CHARACTERSET = AL16UTF16

4.测试:
$ cat  bind_varchar_len.txt
--//用于测试PLSQL字符串分配分界点
--// create table t (a varchar2(4000));
declare
v_a varchar2(&&1);
  begin
   for i in 1..&&1 loop
     v_a := rpad('X',i,'X');
     execute immediate 'select /*+ find_me &&1 */ count(*) from t where a=:v_a' using v_a ;
   end loop;
end;
/

SELECT sql_text
      ,sql_id
      ,child_number
      ,executions
      ,parse_calls
      ,loads
      ,invalidations
  FROM v$sql
 WHERE sql_text LIKE '%find_me &&1%' AND sql_text NOT LIKE '%v$sql%' AND sql_text NOT LIKE 'declare%'

SCOTT@book01p> @ txt/bind_varchar_len.txt 1001
PL/SQL procedure successfully completed.
SQL_TEXT                                                     SQL_ID                                  CHILD_NUMBER EXECUTIONS PARSE_CALLS      LOADS INVALIDATIONS
------------------------------------------------------------ --------------------------------------- ------------ ---------- ----------- ---------- -------------
select /*+ find_me 1001 */ count(*) from t where a=:v_a      gwm6t1hu54cuc                                      0         32           1          1             0
select /*+ find_me 1001 */ count(*) from t where a=:v_a      gwm6t1hu54cuc                                      1         96           0          1             0
select /*+ find_me 1001 */ count(*) from t where a=:v_a      gwm6t1hu54cuc                                      2        873           0          1             0
--//按照实际的长度分配。

5.测试sqlplus for linux。
SCOTT@book01p> variable v_b varchar2(90)
SCOTT@book01p> exec :v_b := rpad('a',90,'a');
PL/SQL procedure successfully completed.
SCOTT@book01p> select * from t where a=:v_b;
no rows selected

SCOTT@book01p> @ hashz

HASH_VALUE SQL_ID                                  CHILD_NUMBER KGL_BUCKET HASH_HEX   SQL_EXEC_START      SQL_EXEC_ID
---------- --------------------------------------- ------------ ---------- ---------- ------------------- -----------
3009098523 7p9qv56tpqcsv                                      0      78619  b35b331b  2025-07-29 11:23:56    16777216

SCOTT@book01p> @ bind_cap 7p9qv56tpqcsv ''
SQL_ID        CHILD_NUMBER WAS_CAPTU NAME POSITION MAX_LENGTH LAST_CAPTURED       DATATYPE_STRING VALUE_STRING                                          INST_ID
------------- ------------ --------- ---- -------- ---------- ------------------- --------------- -------------------------------------------------- ----------
7p9qv56tpqcsv            0 YES       :V_B        1       2000 2025-07-29 11:23:56 VARCHAR2(2000)  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa          1
                                                                                                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

--//使用DATATYPE_STRING=2000.按照以前的介绍使用128就可以。明显定义90并不是真正的保存字符串长度。
--//使用10046跟踪,首先分析表。

SCOTT@book01p> @ 10046on 12
Session altered.

SCOTT@book01p> Select * from t where a=:v_b;
no rows selected
--//注意换成大写SE,主要目的重新分析。

SCOTT@book01p> @ 10046off
Session altered.

=====================
PARSING IN CURSOR #139946379010480 len=28 dep=0 uid=109 oct=3 lid=109 tim=9911309892 hv=2040552028 ad='65bed278' sqlid='7wr0faxwu0qkw'
SElect * from t where a=:v_b
END OF STMT
PARSE #139946379010480:c=743,e=1326,p=0,cr=3,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=9911309892
BINDS #139946379010480:

 Bind#0
  oacdty=01 mxl=2000(180) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=01 csi=852 siz=2000 off=0
  kxsbbbfp=7f47ce3f3410  bln=2000  avl=90  flg=05
  value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
EXEC #139946379010480:c=1582,e=1464,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1601196873,tim=9911311432
WAIT #139946379010480: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=9911311489
FETCH #139946379010480:c=8,e=9,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1601196873,tim=9911311528
STAT #139946379010480 id=1 cnt=0 pid=0 pos=1 obj=145919 op='TABLE ACCESS FULL T (cr=0 pr=0 pw=0 str=1 time=10 us cost=2 size=2002 card=1)'

*** 2025-07-29T11:32:34.162052+08:00 (BOOK01P(3))
WAIT #139946379010480: nam='SQL*Net message from client' ela= 9795519 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=9921107142
CLOSE #139946379010480:c=11,e=11,dep=0,type=0,tim=9921107248
=====================
--//字符串实际长度 avl=90,mxl=2000(180),变成90*2=180,作者的测试是*3,其python的测试是*4,不知道其数据库字符集以及环境的设置。
--//可以在plsql与sqlplus两者的不同。
--//贴上原始作者测试的情况var v varchar2(90)。
Bind#0
  oacdty=01 mxl=2000(270) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=01 csi=873 siz=2000 off=0
  kxsbbbfp=7f9982103b40  bln=2000  avl=04  flg=05
  value="AAAA"
--//csi不同。

6.测试sqlplus for windows。

SCOTT@book01p> variable v_b varchar2(90)
SCOTT@book01p> exec :v_b := rpad('a',90,'a');

PL/SQL procedure successfully completed.

SCOTT@book01p> SELect * from t where a=:v_b;

no rows selected

SCOTT@book01p> @ hashz
HASH_VALUE SQL_ID        CHILD_NUMBER KGL_BUCKET HASH_HEX   SQL_EXEC_START      SQL_EXEC_ID
---------- ------------- ------------ ---------- ---------- ------------------- -----------
1213882039 cy0aw6945nrpr            0      24247  485a5eb7  2025-07-29 11:50:54    16777216

SCOTT@book01p> @ bind_cap cy0aw6945nrpr ''
SQL_ID        CHILD_NUMBER WAS NAME   POSITION MAX_LENGTH LAST_CAPTURED       DATATYPE_STRING VALUE_STRING                                          INST_ID
------------- ------------ --- ---- ---------- ---------- ------------------- --------------- -------------------------------------------------- ----------
cy0aw6945nrpr            0 YES :V_B          1        128 2025-07-29 11:50:54 VARCHAR2(128)   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa          1
                                                                                              aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
--//使用DATATYPE_STRING=128.

7.收尾还原。

--//环境变量LANG=en_US
# cat /etc/locale.conf
#LANG="en_US.UTF-8"
LANG="en_US"

--//修改环境变量
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/267265/viewspace-3092521/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
熟悉oracle相关技术,擅长sql优化,rman备份与恢复,熟悉linux shell编程。

注册时间:2008-01-03

  • 博文量
    4006
  • 访问量
    7969431