[20190102]關於字串的分配問題(10g).txt
[20190102]關於字串的分配問題(10g).txt
--//連結:http://www.itpub.net/thread-2107534-1-1.html提到的問題,裡面一段英文讀起來很繞口:
--//百度找到如下內容:https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/datatypes.htm
VARCHAR2 Datatype
You use the VARCHAR2 datatype to store variable-length character data. How the data is represented internally depends on
the database character set. The VARCHAR2 datatype takes a required parameter that specifies a maximum size up to 32767
bytes. The syntax follows:
VARCHAR2(maximum_size [CHAR | BYTE])
You cannot use a symbolic constant or variable to specify the maximum size; you must use an integer literal in the range
1 .. 32767.
Small VARCHAR2 variables are optimized for performance, and larger ones are optimized for efficient memory use. The
cutoff point is 2000 bytes. For a VARCHAR2 that is 2000 bytes or longer, PL/SQL dynamically allocates only enough memory
to hold the actual value. For a VARCHAR2 variable that is shorter than 2000 bytes, PL/SQL preallocates the full declared
length of the variable. For example, if you assign the same 500-byte value to a VARCHAR2(2000 BYTE) variable and to a
VARCHAR2(1999 BYTE) variable, the former takes up 500 bytes and the latter takes up 1999 bytes.
--//裡面的內容來之這裡.簡單點就是小的varchar2變數最佳化為效能,大的varchar2變數最佳化記憶體使用.分界點在2000位元組.
--//貼一段金山詞霸的翻譯:
小的VARCHAR 2變數是為了效能而最佳化的,較大的變數是為了高效的記憶體使用而最佳化的。截止點是2000位元組。對於2000位元組或更長的
VARCHAR 2,PL/SQL動態分配的記憶體僅足以容納實際值。對於小於2000位元組的VARCHAR 2變數,PL/SQL將分配變數的完整宣告長度。例如,
如果將相同的500位元組值分配給VARCHAR 2(2000位元組)變數和VARCHAR 2(1999位元組)變數,則前者佔500個位元組,後者佔1999年位元組。
If you specify the maximum size in bytes rather than characters, a VARCHAR2(n) variable might be too small to hold n
multibyte characters. To avoid this possibility, use the notation VARCHAR2(n CHAR) so that the variable can hold n
characters in the database character set, even if some of those characters contain multiple bytes. When you specify the
length in characters, the upper limit is still 32767 bytes. So for double-byte and multibyte character sets, you can
only specify 1/2 or 1/3 as many characters as with a single-byte character set.
Although PL/SQL character variables can be relatively long, you cannot insert VARCHAR2 values longer than 4000 bytes
into a VARCHAR2 database column.
You can insert any VARCHAR2(n) value into a LONG database column because the maximum width of a LONG column is
2147483648 bytes or two gigabytes. However, you cannot retrieve a value longer than 32767 bytes from a LONG column into
a VARCHAR2(n) variable. Note that the LONG datatype is supported only for backward compatibility; see "LONG and LONG RAW
Datatypes" more information.
When you do not use the CHAR or BYTE qualifiers, the default is determined by the setting of the NLS_LENGTH_SEMANTICS
initialization parameter. When a PL/SQL procedure is compiled, the setting of this parameter is recorded, so that the
same setting is used when the procedure is recompiled after being invalidated.
--//注意該文件是10gR2下的.放假前在12c上測試過,分界點是1001個字元.
--//補充測試10g的情況:
--//參考連結如下:
--//http://blog.itpub.net/267265/viewspace-746524/ => [20160224]繫結變數的分配長度.txt
--//http://blog.itpub.net/267265/viewspace-1993495/ => [20121016]字串長度與繫結變數的子游標.txt
--//http://blog.itpub.net/267265/viewspace-2287070/=> [20181229]關於字串的分配問題.txt
1.環境:
SCOTT@test> @ &r/ver1
PORT_STRING VERSION BANNER
------------------------------ -------------- ----------------------------------------------------------------
x86_64/Linux 2.4.xx 10.2.0.4.0 Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
SCOTT@test> create table t (a varchar2(4000));
Table created.
--//分析略.
--//建立指令碼len.txt
declare
instring varchar2(&&1);
begin
for i in 1..1000 loop
instring := rpad('X',i,'X');
execute immediate 'select /*+ find_me &&1 */ count(*) from t where a=:instring' using instring ;
end loop;
end;
/
2.測試一:
--//執行 @ len.txt 1999
SCOTT@test> @ len.txt 1999
PL/SQL procedure successfully completed.
--//執行完成後確定sql_id=4yqsjj26q8s1s
SCOTT@test> select sql_text,sql_id,child_number,executions,parse_calls,loads,invalidations from v$sql where sql_id='4yqsjj26q8s1s';
SQL_TEXT SQL_ID CHILD_NUMBER EXECUTIONS PARSE_CALLS LOADS INVALIDATIONS
------------------------------------------------------------ ------------- ------------ ---------- ----------- ---------- -------------
select /*+ find_me 1999 */ count(*) from t where a=:instring 4yqsjj26q8s1s 0 32 1 1 0
select /*+ find_me 1999 */ count(*) from t where a=:instring 4yqsjj26q8s1s 1 96 0 1 0
select /*+ find_me 1999 */ count(*) from t where a=:instring 4yqsjj26q8s1s 2 872 0 1 0
--//很明顯10g關於這個問題的分界點也不是1999或者2000.
SCOTT@test> @ len.txt 1000
PL/SQL procedure successfully completed.
--//確定sql_id=4mv1hkjru31tp
SCOTT@test> select sql_text,sql_id,child_number,executions,parse_calls,loads,invalidations from v$sql where sql_id='4mv1hkjru31tp';
SQL_TEXT SQL_ID CHILD_NUMBER EXECUTIONS PARSE_CALLS LOADS INVALIDATIONS
------------------------------------------------------------ ------------- ------------ ---------- ----------- ---------- -------------
select /*+ find_me 1000 */ count(*) from t where a=:instring 4mv1hkjru31tp 0 1000 1 1 0
SCOTT@test> @ &r/bind_cap 4mv1hkjru31tp ''
C200
------------------------------------------------------------
select /*+ find_me 1000 */ count(*) from t where a=:instring
SQL_ID CHILD_NUMBER WAS NAME POSITION MAX_LENGTH LAST_CAPTURED DATATYPE_STRING VALUE_STRING
------------- ------------ --- -------------------- ---------- ---------- ------------------- --------------- -------------------
4mv1hkjru31tp 0 YES :INSTRING 1 2000 2019-01-02 08:50:28 VARCHAR2(2000) X
--//你可以發現查詢v$sql_bind_capture檢視,裡面DATATYPE_STRING記錄的是VARCHAR2(2000),而我定義的大小是varchar2(1000).
--//當然oracle按照定義不會分配2000空間,而是最大1000.
--//許多人都知道,如果字串繫結變數長度變化會產生子游標.
--//透過測試可以知道字串的長度變化是32,32+96=128,32+96+1872=2000.也就是分4個段 1-32,33-128,129-2000,2001-4000.
--//參考連結:http://blog.itpub.net/267265/viewspace-746524/
--//如果開始分配的字串空間是按照實際使用大小來分配的,就會出現至少3個子游標的情況.而現在僅僅出現1個,說明oracle在開始執行就
--//分配1000個字元空間.
3.測試二:
SCOTT@test01p> alter system flush shared_pool ;
System altered.
--//修改引數1001,執行 @ len.txt 1001
SCOTT@test> @ len.txt 1001
PL/SQL procedure successfully completed.
--//確定sql_id=as5nq40yutw9t
SCOTT@test> select sql_text,sql_id,child_number,executions,parse_calls,loads,invalidations from v$sql where sql_id='as5nq40yutw9t';
SQL_TEXT SQL_ID CHILD_NUMBER EXECUTIONS PARSE_CALLS LOADS INVALIDATIONS
------------------------------------------------------------ ------------- ------------ ---------- ----------- ---------- -------------
select /*+ find_me 1001 */ count(*) from t where a=:instring as5nq40yutw9t 0 32 1 1 0
select /*+ find_me 1001 */ count(*) from t where a=:instring 1 96 0 1 0
select /*+ find_me 1001 */ count(*) from t where a=:instring 2 872 0 1 0
SCOTT@test> @ &r/bind_cap as5nq40yutw9t ''
C200
------------------------------------------------------------
select /*+ find_me 1001 */ count(*) from t where a=:instring
SQL_ID CHILD_NUMBER WAS NAME POSITION MAX_LENGTH LAST_CAPTURED DATATYPE_STRING VALUE_STRING
------------- ------------ --- -------------------- ---------- ---------- ------------------- --------------- --------------------------------------------------
as5nq40yutw9t 0 YES :INSTRING 1 32 2019-01-02 08:53:38 VARCHAR2(32) X
1 YES :INSTRING 1 128 2019-01-02 08:53:38 VARCHAR2(128) XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2 YES :INSTRING 1 2000 2019-01-02 08:53:38 VARCHAR2(2000) XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
--//我僅僅修改字串的定義varchar2(1001),就導致相似的語句產生3個子游標。
--//說明一個問題當字串長度大於1000時,oracle字串的分配按需來分配,這樣就會出現3個子游標的情況.
--//從執行次數上可以看出長度變化1-32, 33- 128(32+96),129-2000(2000可以從v$sql_bind_capture檢視的DATATYPE_STRING確定).
--//可以看出10g與11g,12c版本一樣,分界點是1001.估計oracle文件更新不及時.
4.附上bind_cap.sql的指令碼.
$ cat bind_cap.sql
set verify off
column value_string format a50
column datatype_string format a15
break on sql_id on child_number skip 1
select replace(sql_fulltext,chr(13),'') c200 from v$sql where sql_id='&1' and rownum<=1;
SELECT sql_id,
child_number,
was_captured,
name,
position,
max_length,
last_captured,
datatype_string,
DECODE (
datatype_string,
'DATE', TO_CHAR (TO_DATE (value_string, 'mm/dd/yy hh24:mi:ss'),
'yyyy/mm/dd hh24:mi:ss'),
value_string)
value_string
FROM v$sql_bind_capture
WHERE sql_id = '&1' and was_captured='YES' and DUP_POSITION is null and name=nvl('&&2',name)
order by child_number,was_captured,position;
break on sql_id on child_number skip 0
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-2287101/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [20181229]關於字串的分配問題.txt字串
- 關於字串中取相同的字元問題(小學題)字串字元
- 回覆網友問題,關於一個數值和字串一起累加的問題!字串
- 一些關於VB中字串操作的問題和回答 (轉)字串
- [20200416]關於軟軟解析的問題.txt
- [20140218]關於SDO_GEORASTER的問題.txtAST
- 關於SQLServerDriver的問題SQLServer
- 關於 JavaMail 的問題JavaAI
- 關於session的問題Session
- 關於PHP字串的一道面試題PHP字串面試題
- 關於Oracle10g中tempfile 空間分配的問題:temp file will not actually allocate disOracle
- [20161108]關於資料檔案的問題.txt
- [20171228]關於資料塊轉儲的問題.txt
- [20121108]關於克隆資料庫的問題.txt資料庫
- [20190918]關於函式索引問題.txt函式索引
- [20150304]關於sql格式化問題.txtSQL
- [20210528]oracle大表空間預分配問題.txtOracle
- 關於javascript的this指向問題JavaScript
- 關於跨域的問題跨域
- 關於bit code的問題
- 關於序列同步的問題
- 關於IP地址的問題
- 關於橋模式的問題模式
- 求救 關於parallel的問題Parallel
- 關於web start的問題Web
- 關於action的error問題Error
- 關於ADAPTER的問題APT
- 關於session的奇怪問題Session
- php關於session的問題PHPSession
- 關於diag程式的問題
- 關於SimpleJdonFrameworkTest的問題Framework
- 關於 Puerts 的效能問題
- 關於盒模型相關的問題模型
- 關於oracle 11g客戶端匯出10g庫的問題Oracle客戶端
- 關於FastHashMap問題ASTHashMap
- 關於Oracle10g中tempfile 空間分配的問題:temp file will not actually allocate disk spaceOracle
- [20211018]運維中關於history的問題.txt運維
- [20230317]關於TIME_WAIT問題.txtAI