[20181229]關於字元串的分配問題.txt

来源:https://www.cnblogs.com/lfree/archive/2018/12/31/10203206.html
-Advertisement-
Play Games

[20181229]關於字元串的分配問題.txt--//鏈接:http://www.itpub.net/thread-2107534-1-1.html提到的問題,裡面一段英文讀起來很繞口:--//百度找到如下內容:https://docs.oracle.com/cd/B19306_01/appdev ...


[20181229]關於字元串的分配問題.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下的.
--//突然想起我以前的測試,可以驗證11g改動分界點,實際上是1001個字元.當時測試的鏈接如下:
--//http://blog.itpub.net/267265/viewspace-746524/  => [20160224]綁定變數的分配長度.txt
--//http://blog.itpub.net/267265/viewspace-1993495/ => [20121016]字元串長度與綁定變數的子游標.txt
--//裡面提到1個情況,我當時沒搞清楚,看完上面的鏈接一下明白過來,我通過重覆測試來說明問題。

1.環境:
SCOTT@test01p> @ ver1
PORT_STRING          VERSION    BANNER                                                                       CON_ID
-------------------- ---------- ---------------------------------------------------------------------------- ------
IBMPC/WIN_NT64-9.1.0 12.2.0.1.0 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production      0

SCOTT@test01p> 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 1000
--//執行完成後確定sql_id=4mv1hkjru31tp
SCOTT@test01p> 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@test01p> @ 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 2018-12-30 20:18:38 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@test01p> @ len.txt 1001
PL/SQL procedure successfully completed.
--//確定sql_id=as5nq40yutw9t

SCOTT@test01p> 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 as5nq40yutw9t            1         96           0     1             0
select /*+ find_me 1001 */ count(*) from t where a=:instring as5nq40yutw9t            2        872           0     1             0

SCOTT@test01p> @ 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 2018-12-30 20:30:47 VARCHAR2(32)    X
                         1 YES :INSTRING        1        128 2018-12-30 20:30:47 VARCHAR2(128)   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
                         2 YES :INSTRING        1       2000 2018-12-30 20:30:47 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確定).

3.繼續測試:
--//面前的測試在PL/SQL進行的,在sqlplus測試看看.
SCOTT@test01p> alter system flush shared_pool;
System altered.

variable instring varchar2(1000)
exec :instring := rpad('X',1);
Select /*+ find_me */ count(*) from t where a=:instring;
--//確定sql_id=383pcxarzpwbg.

SCOTT@test01p> @ bind_cap 383pcxarzpwbg ''
C200
-------------------------------------------------------
Select /*+ find_me */ count(*) from t where a=:instring

SQL_ID        CHILD_NUMBER WAS NAME                   POSITION MAX_LENGTH LAST_CAPTURED       DATATYPE_STRING VALUE_STRING
------------- ------------ --- -------------------- ---------- ---------- ------------------- --------------- ------------------
383pcxarzpwbg            0 YES :INSTRING                     1       2000 2018-12-30 20:42:17 VARCHAR2(2000)  X


SCOTT@test01p> alter system flush shared_pool;
System altered.

variable instring varchar2(1001)
exec :instring := rpad('X',1);
Select /*+ find_me 1001x */ count(*) from t where a=:instring;
--//確定sql_id=fd4dr46guv82z
SCOTT@test01p> @ bind_cap fd4dr46guv82z ''
C200
-------------------------------------------------------------
Select /*+ find_me 1001x */ count(*) from t where a=:instring

SQL_ID        CHILD_NUMBER WAS NAME                   POSITION MAX_LENGTH LAST_CAPTURED       DATATYPE_STRING VALUE_STRING
------------- ------------ --- -------------------- ---------- ---------- ------------------- --------------- --------------------
fd4dr46guv82z            0 YES :INSTRING                     1       2000 2018-12-30 20:44:41 VARCHAR2(2000)  X

--//可以看出sqlplus就不是這樣,按照定義分配.而僅僅PL/sql比較特殊.存在1個1001分界點.

4.上面文檔是來自10g的官方文檔.要找一個10g的版本重覆測試看看,驗證是否是2000.
--//等上班找個10g的環境來測試看看.

5.附上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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 2018年還有幾天就結束了,回顧一下今年的博客blog-posts, 簡單整理一下行業與軟體過程(Software Industry & process improvement) 關註軟體過程改進到效能改進,除了軟體開發,還是軟體測試。全球Scrum在應用中,全球軟體測試行業演化;不必多說,研... ...
  • 1. 前言 KASAN是一個動態檢測記憶體錯誤的工具。KASAN可以檢測全局變數、棧、堆分配的記憶體發生越界訪問等問題。功能比SLUB DEBUG齊全並且支持實時檢測。越界訪問的嚴重性和危害性通過我之前的文章(SLUB DEBUG技術)應該有所瞭解。正是由於SLUB DEBUG缺陷,因此我們需要一種更加 ...
  • 1、首先查找tomcat目錄 ? 1 sudo find / -name *shutdown.sh* ? 1 sudo find / -name *shutdown.sh* ? 1 sudo find / -name *shutdown.sh* ? 1 sudo find / -name *shut ...
  • lfs學習筆記(三)鏈接:https://www.cnblogs.com/renren-study-notes/p/10199381.html 一名linux愛好者,記錄構建Linux From Scratch的過程 經博客園-駿馬金龍前輩介紹,開始接觸學習lfs,用博客記錄學習筆記,如有寫的不恰當 ...
  • 一名linux愛好者,記錄構建Linux From Scratch的過程 經博客園-駿馬金龍前輩介紹,開始接觸學習lfs,用博客記錄學習筆記,如有寫的不恰當的地方,望多多指正。筆記中只是記錄一些問題和書中表述不清晰的內容的處理辦法以及我的解決思路,僅做參考。 要實際構建lfs請結合lfs官方的書籍操 ...
  • Ftrace簡介 Ftrace是Linux進行代碼級實踐分析最有效的工具之一,比如我們進行一個系統調用,出來的時間過長,我們想知道時間花哪裡去了,利用Ftrace就可以追蹤到一級級的時間分佈。 Ftrace案例 寫一個proc模塊,包含一個proc的讀和寫的入口。test_proc_show()故意 ...
  • 先來一張餅狀: 時鐘功耗最高: 時鐘單元有 時鐘發生器、時鐘驅動、時鐘樹 和 控制單元。 數據通路其次:主要來自運算單元、匯流排 和 寄存器。 儲存單元: 單位消耗很小,與容量相關,單片機RAM這塊容量很小。 控制部分 輸入輸出 微處理器組成基礎單元COMS 的電源消耗組成: (其他工藝也可以參考,本 ...
  • 一 監控架構 1.1 組成 客戶端:數據採集部分 服務端:數據存儲分析告警展示 1.2 採集模式 被動模式:伺服器端到客戶端採集數據,對伺服器的開銷較大,適合小規模的監控環境。 主動模式:客戶端主動上報數據到伺服器端,對伺服器的開銷較小,適合大規模的監控環境。 1.4 協議 專用客戶端採集 公用協議 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...