[20181229]关于字符串的分配问题.txt
[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
[20181229]关于字符串的分配问题.txt的更多相关文章
- java的io操作(将字符串写入到txt文件中)
import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java ...
- 将字符串写进txt中方式
try { File file = new File(filePath); PrintStream ps = new PrintStream(new FileOutputStream(file)); ...
- js 把字符串保存为txt文件,并下载到本地
代码如下 exportRaw('text.txt','123123123') function fakeClick(obj) { var ev = document.createEvent(" ...
- matlab 以excel格式将字符串数组写入TXT文件
[m, n] = size(FFoutpu);fp = fopen('FFoutpu.txt','wt');fprintf(fp, 'name CODE ROTC EBIT_EV SHIZHI ROT ...
- 将excel中某列数据中,含有指定字符串的记录取出,并生成用这个字符串命名的txt文件
Python 一大重要的功能,就是可处理大量数据,那分不开的即是使用Excel表格了,这里我做下学习之后的总结,望对我,及广大同仁们是一个帮助Python处理Excel数据需要用到2个库:xlwt 和 ...
- 提取一个txt 文档中含指定字符串的所有行
将一个txt 文档中含指定字符串内容的所有行提取出来并保存至新的txt文档中 例如,要提取 1.txt 中所有包含”aaa” 的行的内容 只需在此文件夹中新建一个bat文件,输入以下代码,双击运行,便 ...
- 【转载】SHELL字符串处理技巧(${}、##、%%)
转载自:http://www.cnblogs.com/pmars/archive/2013/02/17/2914444.html 在SHELL编程中,经常要处理一些字符串变量.比如,计算长度啊.截取子 ...
- shell 提取字符串
记录一下: 我们可以用 ${ } 分别替换获得不同的值: file=/dir1/dir2/dir3/my.file.txt ${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/d ...
- 一个可以将 json 字符串 直接绑定到 view 上的Android库
android-data-binding 这是一个可以将 json 字符串 直接绑定到 view 上的库, 不用先将 json 转换为 model 类. 传送门(https://github.com/ ...
随机推荐
- ELK实践(二):收集Nginx日志
Nginx访问日志 这里补充下Nginx访问日志使用的说明.一般在nginx.conf主配置文件里需要定义一种格式: log_format main '$remote_addr - $remote_u ...
- 第一个NHibernateDemo
什么是Nhibernate,Nhibernate是一个面向.Net环境的对 象/关系数据库映射工具.(ORM) 1.搭建项目基本框架: (1)创建MVC项目,命名为NHShop.Web. (2)依次分 ...
- 浅谈Mybatis连接原理
众所周知数据库连接的过程,但是最近面试的人(菜面菜),都说用的SSM框架,但是我问了一下,mybatis是怎么连接上mysql的,基本上都会说:配置好的,直接用了,今天我来抛砖引玉一下,欢迎拍砖! 什 ...
- 使用ES6新数组方法(象C# Lambda表达式一样写查询语句)
let people = [ {id: 1, name: "a", age: 12}, {id: 2, name: "b", age: 13}, {id: 3, ...
- python集合类型
集合类型简介 集合也是容器,其内元素都是无序.唯一.不可变的.它常用来做成员测试.移除重复数据.数据计算(比如交集.并集.差集). 集合Set是dict的无value版.集合也使用大括号包围: > ...
- Go基础系列:双层channel用法示例
Go channel系列: channel入门 为select设置超时时间 nil channel用法示例 双层channel用法示例 指定goroutine的执行顺序 双层通道的解释见Go的双层通道 ...
- linux学习基础1
简介 包含计算机组成,发行.核心思想.主要目录,一些命令ifconfig.echo.tty.startx.export.pwd.history.shutdown.poweroff.reboot.hwc ...
- 高性能MySQL笔记
锁粒度:表锁.行级锁 表锁锁定整张表 隔离级别: 未提交读:事务中的修改,即使没有提交,对其他事务也是可见的.事务可以读取未提交的数据,也被称为脏读.实际应用中比较少用 提交读:一个事务提交之前,所做 ...
- 如何快速将一个list<a>集合中的部分字段值组合成新的的list<b>部分*
有的时候,我们只需要从老数据中拿一部分数据作为新的绑定数据,比如说绑定下拉框的时候需要构造我们需要的数据格式可以采用以下的方法 public class SelectDataViewModel { p ...
- .Net C# 使用Redis
Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工作由VMware主 ...