[20141008]索引字符串的长度问题.txt

[20141008]索引字符串的长度问题.txt

--oracle 的B tree 索引,一般保存方式是长度+键值+...+长度+rowid键值,如果索引唯一,rowid在前面(没有长度指示器),这样可以节省1个字节.
--但是如果索引的字符串长度长度比如超过255个字符,这样索引的长度部分如何保存呢?

--曾经写过一篇"varchar2(4000)如何保存",链接如下:

http://blog.itpub.net/267265/viewspace-747304/

        如果一行能被存储于一个数据块(data block)中,那么其行头(row header)所需容量将不少于 3 字节(byte)。在行头信息之后依次
储存的是各列的列长(column length)及列值(column value)。列长存储于列值之前,如列值不超过250 字节,那么 Oracle使用1字节存
储其列长;如列值超过 250 字节,则使用 3 字节存储其列长。列数据(column data)所需的存储空间取决于此列的数据类型(datatype)。
如果某列的数据类型为变长(variable length)的,那么存储此列值所需的空间可能会随着数据更新而增长或缩小。

总结:
1.如果列值长度小于等于250字节,Oracle使用1字节存储其列长.内容为字段的长度.
2.如果列值长度超过250字节,则使用3字节存储其列长。前面1个字节使用0xfe(表示超过250),后面2个字节表示列值长度.

--所以,我开始想这个应该跟字符串在数据块的保存方式一致,实际情况呢?做一个测试看看:

1.建立测试环境:

SCOTT@test> @ver
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

create table t ( a varchar2(200),b varchar2(3000));
insert into t values (lpad('1',127,'1'),lpad('a',127,'a'));
insert into t values (lpad('2',127,'2'),lpad('b',128,'b'));
insert into t values (lpad('3',127,'3'),lpad('c',1000,'c'));
commit;
create index i_t_a_b on t(a,b);
exec dbms_stats.gather_table_stats(ownname=>user, tabname=>'t', estimate_percent=>null, method_opt=>'FOR ALL COLUMNS SIZE 1');

2.转储索引信息:
SCOTT@test> select segment_name,header_file,header_block from dba_segments where owner=user and segment_name='I_T_A_B';
SEGMENT_NAME         HEADER_FILE HEADER_BLOCK
-------------------- ----------- ------------
I_T_A_B                        4          562

--4*127+128+1000=1636,可以估计应该都保存在索引的root节点.为EADER_BLOCK+1.

alter system checkpoint ;
alter system dump datafile 4 block 563 ;

Leaf block dump
===============
header address 182927614564=0x2a9755e264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 3
kdxcosdc 0
kdxconro 3
kdxcofbo 42=0x2a
kdxcofeo 6361=0x18d9
kdxcoavs 6319
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8032
row#0[7767] flag: ------, lock: 0, len=265
col 0; len 127; (127):
31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31
...
31 31
col 1; len 127; (127):
61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
...
61 61
col 2; len 6; (6):  01 00 02 13 00 00
row#1[7500] flag: ------, lock: 0, len=267
col 0; len 127; (127):
32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32
...
32 32
col 1; len 128; (128):
62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62
...
62 62 62
col 2; len 6; (6):  01 00 02 13 00 01
row#2[6361] flag: ------, lock: 0, len=1139
col 0; len 127; (127):
33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33
...
33 33
col 1; len 1000; (1000):
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
....
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
col 2; len 6; (6):  01 00 02 13 00 02
----- end of leaf block dump -----
End dump data blocks tsn: 4 file#: 4 minblk 563 maxblk 563

--可以发现第一条索引条目前面的flag,lock占用2个字节 1+127+1+127+1+6=263, 2+263=265,正好符合.
--但是第二条索引条目,仅仅b字段增加1个字节,应该总厂266才对,而实际上是267.why?

SCOTT@test> @10to16 1000
10 to 16 HEX   REVERSE16
-------------- ------------------
00000000003e8 0xe8030000

--从转储内容看:
Dump of memory from 0x0000002A9755E200 to 0x0000002A97560200
2A9755E200 0000A206 01000233 B7C4186D 04010002  [....3...m.......]
2A9755E210 0000C7B6 00046F02 0004735E B7C4186B  [.....o..^s..k...]
2A9755E220 00000002 00320002 01000230 00000000  [......2.0.......]
2A9755E230 00000000 00000000 00000000 00000000  [................]
2A9755E240 00000000 0000FFFF 00000000 00000000  [................]
2A9755E250 00000000 00028000 B7C4186B 00000000  [........k.......]
2A9755E260 00000000 03800000 00000000 002A0003  [..............*.]
2A9755E270 18AF18D9 00000000 00000000 00000000  [................]
2A9755E280 00000000 00001F60 1D4C1E57 AAAA18D9  [....`...W.L.....]
2A9755E290 AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA  [................]
        Repeat 118 times
2A9755EA00 AAAAAAAA AAAAAAAA 00000000 00000000  [................]
2A9755EA10 00000000 00000000 00000000 00000000  [................]
        Repeat 273 times
2A9755FB30 00000000 00000000 00000000 7F000000  [................]
2A9755FB40 33333333 33333333 33333333 33333333  [3333333333333333]
        Repeat 6 times
2A9755FBB0 33333333 33333333 33333333 83333333  [333333333333333.]
2A9755FBC0 636363E8 63636363 63636363 63636363  [.ccccccccccccccc]  2A9755FBD0 63636363 63636363 63636363 63636363  [cccccccccccccccc]
        Repeat 60 times
2A9755FFA0 63636363 63636363 00010663 02001302  [ccccccccc.......]
2A9755FFB0 327F0000 32323232 32323232 32323232  [...2222222222222]
2A9755FFC0 32323232 32323232 32323232 32323232  [2222222222222222]
        Repeat 6 times
2A97560030 80803232 62626262 62626262 62626262  [22..bbbbbbbbbbbb]  2A97560040 62626262 62626262 62626262 62626262  [bbbbbbbbbbbbbbbb]
        Repeat 6 times
2A975600B0 62626262 02000106 00010013 31317F00  [bbbb..........11]
2A975600C0 31313131 31313131 31313131 31313131  [1111111111111111]
        Repeat 6 times
2A97560130 31313131 31313131 31313131 61617F31  [1111111111111.aa]  2A97560140 61616161 61616161 61616161 61616161  [aaaaaaaaaaaaaaaa]
        Repeat 6 times
2A975601B0 61616161 61616161 61616161 00010661  [aaaaaaaaaaaaa...]
2A975601C0 00001302 00000000 00000000 00000000  [................]
2A975601D0 00000000 00000000 00000000 00000000  [................]
        Repeat 1 times
2A975601F0 00000000 00000000 00000000 186D0601  [..............m.]

对比转储,可以猜测与总结如下:

1.当字符串长度小于等于127时,使用1个字节表示长度.
2.当字符串大于等于128时,使用2个字节来保存长度,内容为字符串长度+0x8000.
3.真搞不懂为什么与数据块的保存方式不同,oracle要创造2种不同的方式保存字符串.

--补充通过bbed观察看看.
BBED> set dba 4,563
        DBA             0x01000233 (16777779 4,563)

BBED> p kd_off
sb2 kd_off[0]                               @132      8032
sb2 kd_off[1]                               @134      0
sb2 kd_off[2]                               @136      7767

--kd_off[1] 指向 0,难道中间靠前面的信息来推断吗? 这个东西不是很理解,先放一下.

BBED> p *kd_off[2]
rowdata[1410]
-------------
ub1 rowdata[1410]                           @7867     0x00

BBED> x /rccx
rowdata[1410]                               @7867
-------------
flag@7867:     0x00 (NONE)
lock@7868:     0x00
data key:
col  0[127] @7870: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
col  1[127] @7998: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
col    2[6] @8126:  0x01  0x00  0x02  0x13  0x00  0x00

BBED> dump /v offset 7997 count 32
File: /u01/app/oracle11g/oradata/test/users01.dbf (4)
Block: 563                                                         Offsets: 7997 to 8028                                                      Dba:0x01000233
---------------------------------------------------------------------------------------------------------------------------------------------------------------
7f616161 61616161 61616161 61616161 61616161 61616161 61616161 61616161                                     l .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

-- 0x7f=127.

BBED> set offset 7600
        OFFSET          7600

BBED> x /rccx
rowdata[1143]                               @7600
-------------
flag@7600:     0x00 (NONE)
lock@7601:     0x00
data key:
col  0[127] @7603: 2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
col  1[128] @7732: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
col    2[6] @7861:  0x01  0x00  0x02  0x13  0x00  0x01

BBED> dump /v offset 7730 count 32
File: /u01/app/oracle11g/oradata/test/users01.dbf (4)
Block: 563                                                         Offsets: 7730 to 7761                                                      Dba:0x01000233
---------------------------------------------------------------------------------------------------------------------------------------------------------------
80806262 62626262 62626262 62626262 62626262 62626262 62626262 62626262                                     l ..bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

--8080表示长度128.

BBED> set offset 6461
        OFFSET          6461

BBED> x /rccx
rowdata[4]                                  @6461
----------
flag@6461:     0x00 (NONE)
lock@6462:     0x00
data key:
col  0[127] @6464: 3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
col 1[1000] @6593: ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
...
cccc
col    2[6] @7594:  0x01  0x00  0x02  0x13  0x00  0x02

BBED> dump /v offset 6591 count 32
File: /u01/app/oracle11g/oradata/test/users01.dbf (4)
Block: 563                                                         Offsets: 6591 to 6622                                                      Dba:0x01000233
---------------------------------------------------------------------------------------------------------------------------------------------------------------
83e86363 63636363 63636363 63636363 63636363 63636363 63636363 63636363                                     l ..cccccccccccccccccccccccccccccc

--83e8 表示长度1000.

时间: 2024-08-20 18:49:36

[20141008]索引字符串的长度问题.txt的相关文章

[20171019]绑定变量的分配长度7.txt

[20171019]绑定变量的分配长度7.txt --//如果绑定变量中字符串分配占用空间的长度变化,oracle会建立子光标. --//参考连接: http://blog.itpub.net/267265/viewspace-1993495/ --//oracle 可以通过一个10503事件设置大的缓存,测试看看: $ oerr ora 10503 10503, 00000, "enable user-specified graduated bind lengths" // *Cau

[20160313]绑定变量的分配长度4.txt

[20160313]绑定变量的分配长度4.txt --如果绑定变量中字符串分配占用空间的长度变化,oracle会建立子光标. --参考连接: http://blog.itpub.net/267265/viewspace-1993495/ http://blog.itpub.net/267265/viewspace-2024389/ http://blog.itpub.net/267265/viewspace-2050886/ --12c支持更长的字符串,顺便测试看看: --关于设置12c支持字串

[20161001]绑定变量的分配长度5.txt

[20161001]绑定变量的分配长度5.txt --如果绑定变量中字符串分配占用空间的长度变化,oracle会建立子光标. --一般如果绑定变量有多个字段在分配占用空间时长度变化,这样生成的子光标会增加. --我以前的测试字符串长度变化是32,32+96=128,32+96+1872=2000.也就是分4个段 1-32,33-128,129-2000,2001-4000. --相关链接: http://blog.itpub.net/267265/viewspace-1993495/ http:

[20160302]绑定变量的分配长度2.txt

[20160302]绑定变量的分配长度2.txt --如果绑定变量中字符串分配占用空间的长度变化,oracle会建立子光标. --参考连接: http://blog.itpub.net/267265/viewspace-1993495/ --oracle 可以通过一个10503事件设置大的缓存,测试看看: $ oerr ora 10503 10503, 00000, "enable user-specified graduated bind lengths" // *Cause: //

[20161002]绑定变量的分配长度6.txt

[20161002]绑定变量的分配长度6.txt --如果绑定变量中字符串分配占用空间的长度变化,oracle会建立子光标. --一般如果绑定变量有多个字段在分配占用空间时长度变化,这样生成的子光标会增加. --我以前的测试字符串长度变化是32,32+96=128,32+96+1872=2000.也就是分4个段 1-32,33-128,129-2000,2001-4000. --相关链接: http://blog.itpub.net/267265/viewspace-1993495/ http:

[20160307]绑定变量的分配长度3.txt

[20160307]绑定变量的分配长度3.txt --如果绑定变量中字符串分配占用空间的长度变化,oracle会建立子光标. --参考连接: http://blog.itpub.net/267265/viewspace-1993495/ http://blog.itpub.net/267265/viewspace-2024389/ --oracle 可以通过一个10503事件设置大的缓存: $ oerr ora 10503 10503, 00000, "enable user-specified

判断的条件是一个字符串的长度

条件|字符串 2004-10-810:49:42青 好好利用时间(f)wingc@SQL也不简单啊吴聪,请教一下sql中,如果判断的条件是一个字符串的长度,比如column1字段的长度是3,如"001"就能入选.这样的条件怎么写??我google it first了2004-10-810:50:37(f)wingc@SQL也不简单啊青 好好利用时间SQL Server中用len(字段名) = 3,试过没?2004-10-810:50:55青 好好利用时间(f)wingc@SQL也不简单

对中英文字符串的长度的一点小解

字符串           对中英文字符串的长度的一点小解                  (jaklin   2000.8.9)        常常有人问到中英文字符串的长度和判断问题, 因为在ASP和SQL7中英文也只占用一个字节.其实是很简单, 只是麻烦一点而已.    一般来说对于中文和英文最大的区别在于它们的ASCII码不同, 因此可以通过它们的ASCII码来判别是不是英文, 并求出字符串的长度.中文的ASCII码值一般大于255.下面的函数是用于求中英文字符串的长度.       

php获取字符串的长度及截取字符串

三.获取字符串的长度:strlen()函数 语法: int strlen(string str); 例: <?php echo strlen("www.bianceng.cn");?> 四.截取字符串:substr()函数 语法: substr(要截取的字符串,开始截取的位置,截取字符的个数) 例: <?php $a="www.bianceng.cn"; echo substr($a,13,2); //输出 cn?> 以上是小编为您精心准备的