非分区键的GLOBAL分区索引键值更新会造成麻烦吗?

我们都知道如果想修改分区表的分区键的值如果跨越了分区,那么必须加入ENABLE ROW MOVEMENT 进行,因为此时可能的ROWID会出现变动,
关于ROWID 如下:
Object ID (4 bytes) + DBA (4 bytes) + Row (2 bytes)
其中DBA包含了BLOCK地址和DATAFILE地址,如果UPDATE分区键的记录,可能的DATAFILE和BLOCK 都需要变动,所以要开启ENABLE ROW MOVEMENT。
而修改分区索引的键值在多个分区中移动为什么没有问题呢?如下:
SQL> CREATE INDEX month_ix ON testpar1(ic)
  2     GLOBAL PARTITION BY RANGE(ic)
  3        (PARTITION pm1_ix VALUES LESS THAN (1000),
  4         PARTITION pm2_ix VALUES LESS THAN (2000),
  5         PARTITION pm3_ix VALUES LESS THAN (3000),
  6         PARTITION pm4_ix VALUES LESS THAN (4000),
  7         PARTITION pm5_ix VALUES LESS THAN (5000),
  8         PARTITION pm6_ix VALUES LESS THAN (6000),
  9         PARTITION pm7_ix VALUES LESS THAN (7000),
 10         PARTITION pm8_ix VALUES LESS THAN (8000),
 11         PARTITION pm12_ix VALUES LESS THAN (MAXVALUE));
建立一个范围分区索引,然后我们进行UPDATE跨分区的,注意这里使用GLOBAL分区,这样我们我们用于测试修改非表分区字段,而是分区索引字段的值进行变动分区
SQL> update testpar1 set ic=10040 where ic=999;
1 row updated

此行必然造成分区间的移动数据,但是是没有问题的,如下我们通过DUMP进行仔细的分析一次

进行索引块截取一部分
row#0[8020] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 02
col 1; len 6; (6):  02 00 0d f3 00 00
row#1[8008] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  02 00 0d f3 00 01
row#2[7996] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 04
col 1; len 6; (6):  02 00 0d f3 00 02

可以看到COL 1就是ROWID,这里的ROWID使用的是SHORT模式如下:
DBA (4 bytes) + Row (2 bytes)
这里我们取值
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  02 00 0d f3 00 01
进行COL0换算
SQL> select to_number('c1','xxxxxx') from dual;
TO_NUMBER('C1','XXXXXX')
------------------------
                     193

SQL> select to_number('03','xxxxxx') from dual;
TO_NUMBER('03','XXXXXX')
------------------------
                       3
指数 193-193=0
数字1 (3-1)*100^0=2

所以这里COL0的数据位实际是2
而ROWID是02 00 0d f3 00 01,进行换算

SQL> select to_number('02000df3','xxxxxxxxx') from dual;
TO_NUMBER('02000DF3','XXXXXXXX
------------------------------
                      33558003
SQL> SELECT dbms_utility.data_block_address_block(33558003) "BLOCK",
  2          dbms_utility.data_block_address_file(33558003) "FILE"
  3       FROM dual;
     BLOCK       FILE
---------- ----------
      3571          8

而0001就是第二行而已,实际这行的ROWID对应了FILE 8 BLOCK 3571的第二行

然后我们取出表中原始记录的ROWID
SQL> select dump(rowid,16) from testpar1 where ic=2;
DUMP(ROWID,16)
--------------------------------------------------------------------------------
Typ=69 Len=10: 0,1,c0,80,2,0,d,f3,0,1
这个结果和INDEX中的ROWID 
col 1; len 6; (6):  02 00 0d f3 00 01
完全一致,然后我们进行对原表记录进行更改进行跨索引跨分区测试
SQL> update testpar1 set ic=30000 where ic=2;
1 row updated

SQL> commit;
Commit complete

这样实际上我们索引记录已经由分区pm1_ix移动到MAXVALUE分区pm12_ix,这种情况下我们再来看源行的ROWID
SQL> select dump(rowid,16) from testpar1 where ic=30000;
DUMP(ROWID,16)
--------------------------------------------------------------------------------
Typ=69 Len=10: 0,1,c0,80,2,0,d,f3,0,1
可以看到ROWID并没有改变,这是一定的。
然后我们在索引中找到这个块,但是如何中得到呢?由于索引是排序好的结构30000是其中最大的数据,找到这个30000的值我们需要找到最后一个有数据的索引块
首先DUMP这个pm12_ix的 BMB LEVEL 3块也就是段头块关注如下数据:
  --------------------------------------------------------
  Segment Type: 2 nl2: 1      blksz: 8192   fbsz: 0      
  L2 Array start offset:  0x00001434
  First Level 3 BMB:  0x00000000
  L2 Hint for inserts:  0x02404cc9
  Last Level 1 BMB:  0x02404cc8
  Last Level II BMB:  0x02404cc9
  Last Level III BMB:  0x00000000
     Map Header:: next  0x00000000  #extents: 2    obj#: 114826 flag: 0x10000000
  Inc # 0 
  Extent Map
  -----------------------------------------------------------------
   0x02404cc8  length: 8     
   0x02404cd0  length: 8     
  
  Auxillary Map
  --------------------------------------------------------
   Extent 0     :  L1 dba:  0x02404cc8 Data dba:  0x02404ccb
   Extent 1     :  L1 dba:  0x02404cc8 Data dba:  0x02404cd0
  --------------------------------------------------------
可以清楚的看到EXTENT 0和1实际由一个L1块进行管理0x02404cc8,然后我们DUMP出这个L1块
关注如下信息:
  --------------------------------------------------------
  DBA Ranges :
  --------------------------------------------------------
   0x02404cc8  Length: 8      Offset: 0      
   0x02404cd0  Length: 8      Offset: 8      
  
   0:Metadata   1:Metadata   2:Metadata   3:25-50% free
   4:FULL   5:FULL   6:FULL   7:FULL
   8:FULL   9:unformatted   10:unformatted   11:unformatted
   12:unformatted   13:unformatted   14:unformatted   15:unformatted
可以看到这里实际到了第九个块8:FULL,注意这里0:Metadata   1:Metadata   2:Metadata 实际上是
BMB 1,BMB 2,段头和BMB 3原数据块。
这样实际我们进行0x02404cd0的DUMP就可以找到数据了。
SQL> select to_number('02404cd0','xxxxxxxxx') from dual;
TO_NUMBER('02404CD0','XXXXXXXX
------------------------------
                      37768400

SQL> 
     BLOCK       FILE
---------- ----------
     19664          9

进行dump发现数据就在最后如下:
row#84[6928] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c3 02
col 1; len 6; (6):  02 40 4c 83 01 e1
row#85[6914] flag: ------, lock: 0, len=14
col 0; len 4; (4):  c3 02 01 29
col 1; len 6; (6):  02 00 0d f5 01 a8
row#86[6902] flag: ------, lock: 2, len=12
col 0; len 2; (2):  c3 04
col 1; len 6; (6):  02 00 0d f3 00 01
----- end of leaf block dump -----
End dump data blocks tsn: 4 file#: 9 minblk 19664 maxblk 19664

这里我们找到了
row#86[6902] flag: ------, lock: 2, len=12
col 0; len 2; (2):  c3 04
col 1; len 6; (6):  02 00 0d f3 00 01
进行换算COL 0

指数 195-193=2
数字1 (4-1)*100^2=30000
可以看出没有问题就是我们修改的哪一行在关注ROWID
col 1; len 6; (6):  02 00 0d f3 00 01

SQL> select dump(rowid,16) from testpar1 where ic=30000;
DUMP(ROWID,16)
--------------------------------------------------------------------------------
Typ=69 Len=10: 0,1,c0,80,2,0,d,f3,0,1

对比没有问题他确实没有变化,这样确切的说明了更改GLOBAL PARTITION INDEX的分区键的值不造成任何问题的原因
在于原表原数据的ROWID没有发生,而在INDEX PARATION中移动是不涉及到ROWID的。所以没有问题

时间: 2024-11-10 10:51:14

非分区键的GLOBAL分区索引键值更新会造成麻烦吗?的相关文章

Oracle Local VS Global分区索引简介

在Oracle中,索引和表一样也可以分区.有两种类型的分区索引,本地分区索引(Local )和全局分区索引(Global). 1.本地索引(Local) 本地分区索引使用 LOCAL关键字创建,其分区边界与表相同(即与每个表分区相关联都有一个索引分区),下面 是一个本地分区索引的例子: create table sales_par partitioned by range (year) ( partition p_2009 values less than (2010) partition p_

索引键的唯一性(1/4):堆表上的唯一与非唯一非聚集索引的区别

原文:索引键的唯一性(1/4):堆表上的唯一与非唯一非聚集索引的区别 在这篇文章里,我想详细介绍下SQL Server里唯一与非唯一非聚集索引的区别.看这个文章前,希望你已经理解了聚集和非聚集索引的概念,还有在SQL Server里是如何使用的. 很多人对唯一和非唯一索引非聚集索引的认识都不是很清晰.事实上,SQL Server在存储上这2类索引有着本质的区别,这些区别会影响到索引占用空间的大小和索引的使用效率. 今天我们从SQL Server里的堆表(Heap table) ,它是没有聚集索引

索引键的唯一性(2/4):唯一与非唯一聚集索引

原文:索引键的唯一性(2/4):唯一与非唯一聚集索引 在上一篇文章里,我们讨论了堆表上唯一/非唯一非聚集索引.在SQL Server里没有聚集索引定义的叫堆表.当你在堆表上定义了一个聚集索引,你的表数据就会重组按聚集键的顺序进行物理存储,因为这个表叫做聚集表.这篇文章里,我想谈下唯一和非唯一聚集索引之间的区别,这2类聚集索引对存储的影响. 看这个文章之前,希望你对聚集索引有个基本的认识,并且知道堆表和聚集表之间的区别,还有当在表上定义了一个聚集索引,表里数据页是如何组织的(B树结构). 我们从唯

sql-SQL相关(分区,更新外键,多个外键关联)

问题描述 SQL相关(分区,更新外键,多个外键关联) 1.分区函数:为什么分区一直报错"数据库中已经存在对象" 代码:use food go create partition function pf_eva_date(datetime) as range left for values(2012) 2.如何在表中更新外键,最好用可视化界面不要脚本(表已建好保存了) 3.如果美食表中,美食有多个,怎么关联这多个外键?

第十二章——SQLServer统计信息(2)——非索引键上统计信息的影响

原文:第十二章--SQLServer统计信息(2)--非索引键上统计信息的影响 前言:         索引对性能方面总是扮演着一个重要的角色,实际上,查询优化器首先检查谓词上的统计信息,然后才决定用什么索引.一般情况下,默认会在创建索引时,索引列上均创建统计信息.但是不代表在非索引键上的统计信息对性能没有用.         如果表上的所有列都有索引,那么将会是数据库负担不起,同时也不是一个好想法,包括谓词中用到的所有列加索引同样也不是好方法.因为索引会带来负载.因为需要空间存放索引,且每个D

索引键的唯一性(3/4):唯一聚集索引上的唯一和非唯一非聚集索引

原文:索引键的唯一性(3/4):唯一聚集索引上的唯一和非唯一非聚集索引 在上篇文章里,我讨论了唯一和非唯一聚集索引的区别.我们已经知道,SQL Server内部使用4 bytes的uniquifier来保证非唯一聚集索引行唯一.今天我们来看下唯一聚集索引上,唯一和非唯一非聚集索引的区别.当我们在表上定义PRIMARY KEY约束时,SQL Server会为我们创建唯一聚集索引:另外我们可以通过CREATE UNIQUE CLUSTERED INDEX语句在表上创建唯一聚集索引.下面的代码会创建c

索引键的唯一性(4/4):非唯一聚集索引上的唯一和非唯一非聚集索引

原文:索引键的唯一性(4/4):非唯一聚集索引上的唯一和非唯一非聚集索引 在上一篇文章里,我谈了唯一聚集索引上的唯一和非唯一非聚集索引的区别.在这篇文章里,我想谈下非唯一聚集索引上的唯一和非唯一聚集索引的区别.我们都知道,SQL Server内部把非唯一聚集索引当作唯一聚集索引处理的.如果你定义了一个非唯一聚集索引,SQL Server会增加叫做uniquifier到你的索引记录,它导致你聚集索引的导航结构(B树的非叶子层)里,每条索引行都要用到4 bytes的开销. 下列代码再次创建我们的Cu

Oracle分区(2) 分区索引

可能很多初学者和我一样,一开始以为只要在分区表上创建的索引就是分区索引,其实不然,索引 是否分区和表是否分区没有必然的关系,表分区索引可以分区也可以不分区,甚至表不分区索引也可 以分区(但很少会这么定义),因此分区索引比分区表要复杂的多. 分区索引主要分为本地分区索引和全局分区索引,本地索引又分为前缀索引和非前缀索引,本文主 要探讨它们的区别. 本地分区索引 本地分区索引是指索引的分区键.分区方式和基表的分区方式一模一样,如下图所示: 本地分区索引具有如下基本特征: 1. 本地索引一定是分区索引

从性能的角度谈SQL Server聚集索引键的选择

简介 在SQL Server中,数据是按页进行存放的.而为表加上聚集索引后,SQL Server对于数据的查找就是按照聚集索引的列作为关键字进行了.因此对于聚集索引的选择对性能的影响就变得十分重要了.本文从旨在从性能的角度来谈聚集索引的选择,但这仅仅是从性能方面考虑.对于有特殊业务要求的表,则需要按实际情况进行选择. 聚集索引所在的列或列的组合最好是唯一的 这个原因需要从数据的存放原理来谈.在SQL Server中,数据的存放方式并不是以行(Row)为单位,而是以页为单位.因此,在查找数据时,S