??xml version="1.0" encoding="utf-8" standalone="yes"?> 两种使用B树在列上建立索引的情况: l 索引用于讉K表中的行Q通过ȝ引来讉K表中的行。此时你希望讉K表中很少的一部分行(只占一个很的癑ֈ比)?/span> l 索引用于回答一个查询:索引包含了够的信息来回{整个查询,我根本不用去讉K表。在q种情况下,索引则用作一?#8220;较瘦“版本的表Q即通过查询索引p扑ֈ查询l果Q在q种情况下,可以通过处理标准100%的数据,而不像第一U情况中只能讉K量的数据?/font> Z么在通过索引讉K表时如果数据量比较大的话Q用烦引反而会降低性能Q?/span> 一般来ԌB*树烦引会攑֜频繁使用查询谓词的列?/font>Q而且我们希望从表中只q回量的数据(只占很小的百分比Q,或者最l用戯求立卛_到反馈。在一个瘦Q?font face="Times New Roman">thinQ表Q也是_只有很少的几个列Q或者列很小Q上Q这个百分比可能相当。用这个烦引的查询应该只获取表?/font>2%?/font>3%Q或者更)的行。在一个胖Q?/font>fatQ表中(也就是说Q这个表有很多列Q或者列很宽Q,癑ֈ比则可能会上升到表的20%?/font>25%。以上徏议不一定直接适用于每一个hQ这个比例ƈ不直观,但很_?/font> 索引按烦引键的顺序存储。烦引会按键的有序顺序进行访问。烦引指向的块则随机地存储在堆中。因此,我们通过索引讉K表时Q会执行大量分散、随机的I/O。这?#8220;分散“Q?/font>scatteredQ是指,索引会告诉我们读取块1Q然后是?/font>1000、块205、块321、块1、块1032、块1Q等{,它不会要求我们按一U连l的方式d?/font>1、然后是?/font>2Q接着是块3Q原因在与表中的每一行ƈ没有按照索引键的序存储在堆中,否则不会出现q种情况Q。我们将以一U非帔R意的方式d和重新读取块。这U块I/O可能非常慢?/font> 下面来看q样一个简化的例子Q假设我们通过索引d一个瘦表,而且要读取表?font face="Times New Roman">20%的行。若q个表中?/font>100,000行,其中?/font>20%是2,0000行。如果行大小Uؓ80字节Q在一个块大小?/font>8KB的数据库中,每个块上则有大约100行。这说明Q这个表有大U?/font>1000个块。了解了q些情况Q计v来就非常Ҏ了。我们要通过索引d20,000行;q说明,大约?/font>20,000?/font>TABLE ACCESS BY ROWID操作。ؓ此要处理20,000个表块来执行q个查询。不q,整个表才有大U?/font>1000个块Q?/font>因而最后会q_把表中的每一个块d和处?font face="Times New Roman">20?/font>Q效果就是缓存的命中率很低,~存的相d的数据没有用刎ͼ?nbsp;即把行的大提高一个数量Q达到每?font face="Times New Roman">800字节Q这h块有11.行,现在表中有11.,000个块。要通过索引讉K20,000行,仍要求我们把每一个块q_d2ơ?/font>在这U情况下Q全表扫描就比用烦引高效得多,因ؓ每个块只会命中一ơ?/span>如果查询使用q个索引来访问数据,效率都不会高Q除非对?font face="Times New Roman">800字节的行Q^均只讉K表中不到5%的数据,因ؓq样一来,只会访问大U?/font>5,000个块Q如果是80字节的行Q则讉K的数据应当只占更的癑ֈ比,大约0.5%或更(q就是ؓ什么在一ơ查询中一?#8220;胖表”的数据获取百分比比一?#8220;瘦表”相对高的原因Q?/font> 因此Q根本原因是因ؓ~存命中率降低,出现了大量随机分散的I/O操作?/font> 物理l织对烦引效率的影响 此外Q数据在盘上如何物理组l,对上q过E也会有显著影响?/span> 表会很自然地按主键顺序聚(因ؓ数据或多或少是已这U属性增加的Q。当Ӟ它不一定严格按照键聚簇Q要惛_到这一点,必须使用一?font face="Times New Roman">IOTQ,但是Q一般来Ԍ主键值彼此接q的行的物理位置也会“?#8220;在一赗如果发Z下查询: select * from T where primary_key between :x and :yQ?/font> 你想要的行通常׃于同L块上。在q种情况下,即要访问大量的行(占很大的癑ֈ比)Q烦引区间扫描可能也很有用。原因在于:我们需要读取和重新d的数据库块很可能会被~存Q因为数据共同放|在同一个位|(co-locatedQ?/font>。另一斚wQ如果行q共同存储在一个位|上Q用这个烦引对性能来讲可能是N性的?/span> 聚簇因子 接下来,我们来看Oracle所用的一些信息。我们要特别查看USER_INDEXES视图中的CLUSTERING_FACTOR列?/font>Oracle reference手册指出了这个列有以下含义: Ҏ索引的值指C中行的有序程度: 如果q个g块数接近Q则说明表相当有序,得到了很好的l织Q在q种情况下,同一个叶子块中的索引条目可能指向同一个数据块上的行?/span> 如果q个g行数接近Q表的次序可能就是非帔R机的。在q种情况下,同一个叶子块上的索引条目不太可能指向同一个数据块上的行?/font> 可以把聚因子(clusteringfactorQ看作是通过索引d整个表时对表执行的逻辑I/Oơ数。也是_CLUSTERING_FACTOR指示了表相对于烦引本w的有序E度Q查看这些烦引时Q会看到以下l果Q?/font> ops$tkyte@ORA10G> select a.index_name, 2 b.num_rows, 3 b.blocks, 4 a.clustering_factor 5 from user_indexes a, user_tables b 6 where index_name in ('COLOCATED_PK', 'DISORGANIZED_PK' ) 7 and a.table_name = b.table_name 8 / INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR --------------- ---------- ---------- ----------------- COLOCATED_PK 100000 1252 1190 DISORGANIZED_PK 100000 1219 99932 所以数据库_“如果通过索引COLOCATED_PK从头到尾地读?/font>COLOCATED表中的每一行,p执行1190?/font>I/O。不q,如果我们?/font>DISORGANIZED表做同样的事情,则会对这个表执行99,932?/font>I/O“。之所以存在这么大的区别,原因在于Q?/font>?font face="Times New Roman">Oracle对烦引结构执行区间扫描时Q如果它发现索引中的下一行几乎M前一行在同一个数据库块上Q就不会再执行另一?/font>I/O从缓冲区~存中获得表块。它已经有表块的一个句柄,只需直接使用可以了。不q,如果下一行不在同一个块上,׃释放当前的这个块Q而执行另一?/font>I/O从缓冲区~存获取要处理的下一个块。因此,在我们对索引执行区间扫描ӞCOLOCATED_PK索引会发C一行几乎M前一行在同一个块上?/font>DISORGANIZED_PK索引发现的情况则恰好相反?/font> 以上讨论的关键点是,索引q不一定L合适的讉KҎ。优化器也许选择不用烦引,而且如前面的例子所C,q种选择可能很正。媄响优化器是否使用索引的因素有很多Q包括物理数据布局。因此,你可能会矫枉q正Q力N建所有的表来使所有烦引有一个好的聚因子,但是在大多数情况下这可能只会费旉。只有当你在对表中的大量数据Q所占百分比很大Q执行烦引区间扫描时Q这才会产生影响。另外必记住,对于一个表来说Q一般只有一个烦引能有合适的聚簇因子Q表中的行可能只以一U方式排序。在前面所C的例子中,如果Y列上q有一个烦引,q个索引?/font>COLOCATED表中可能׃能很好地聚簇Q而在DISORGANIZED表中则恰好相反。如果你认ؓ数据物理聚簇很重要,可以考虑使用一?/font>IOT?/font>B*树聚,或者在q箋地重时考虑散列聚簇?/font> B*树烦引小l?/font> 什么时候徏立烦引,在哪些列上徏立烦引,你的设计中必L意这些问题。烦引ƈ不一定就意味着更快的访问;实际上你会发玎ͼ在许多情况下Q如?font face="Times New Roman">Oracle使用索引Q反而会使性能下降?/font>q实际上两个因素的一个函敎ͼ其中一个因素是通过索引需要访问表中多数据(占多大的癑ֈ比)Q另一个因素是数据如何布局?/span>如果能完全用烦?#8220;回答问题“Q而不用表Q,那么讉K大量的行Q占很大的百分比Q就是有意义的,因ؓq样可以避免读表所带来的额外的分散I/O。如果用烦引来讉K表,可能p保只处理整个表中的很少一部分Q只占很的癑ֈ比)?/font> 应该在应用的设计期间考虑索引的设计和实现Q而不要事后才惌v来(我就l常见到q种情况Q。如果对如何讉K数据做了_ֿ的计划和考虑Q大多数情况下就能清楚地知道需要什么烦引?/span> B* 树烦?/font> q些是我所说的 “ 传统 “ 索引。到目前为止Q这?nbsp;Oracle 和大多数其他数据库中最常用的烦引?nbsp;B* 树的构造类g二叉树,能根据键提供一行或一个行集的快速访问,通常只需很少的读操作p扑ֈ正确的行。不q,需要注意重要的一点, ” B* ?nbsp;“ 中的 ” B “ 不代表二叉( binary Q,而代表^衡( b alanced Q?/font>B* 树烦引ƈ不是一颗二叉树Q这一点在介绍如何在磁盘上物理地存?nbsp;B* 树时׃了解到?nbsp;B* 树烦引有以下子类型: 索引l织表( index organized table Q:索引l织表以 B* 树结构存储?/font>堆表的数据行是以一U无l织的方式存储的Q只要有可用的空_可以放数据Q,?nbsp;IOT 与之不同Q?nbsp;IOT 中的数据要按主键的顺序存储和排序。对应用来说Q?nbsp;IOT 表现得与 “ 常规 “ 表ƈ无二_需要?nbsp;SQL 来正地讉K IOT ?nbsp;IOT 对信息获取、空间系l和 OLAP 应用最为有用?nbsp;IOT 在上一章已l详l地讨论q?/font> B*树聚烦引( B*tree cluster index Q这些是传统 B* 树烦引的一个变体(只是E有变化Q?nbsp;B* 树聚烦引用于对聚簇键徏立烦引(见第 11. 章中 “ 索引聚簇?nbsp;“ 一节)Q所以这一章不再讨论。在传统 B* 树中 Q键都指向一行;?nbsp;B* 树聚不同,一个聚键会指向一个块Q其中包含与q个聚簇键相关的多行?/span> 降序索引Q?nbsp;descending index Q:降序索引允许数据在烦引结构中?nbsp;“ 从大到小 “ 的顺序(降序Q排序,而不是按 ” 从小到大 “ 的顺序(升序Q排序。我们会解释Z么降序烦引很重要Qƈ说明降序索引如何工作?/font> 反向键烦引( reverse key index Q:q也?nbsp;B* 树烦引,只不q键中的字节?nbsp;“ 反{ “ 。利用反向键索引Q如果烦引中填充的是递增的|索引条目在烦引中可以得到更均匀的分布。例如,如果使用一个序列来生成主键Q这个序列将生成诸如 987500 ?nbsp;987501 ?nbsp;987502 {倹{这些值是序的,所以倘若使用一 个传l的 B* 树烦引,q些值就可能攑֜同一个右侧块上,q就加剧了对q一块的竞争。利用反向键Q?nbsp;Oracl e则会逻辑地对 205789 ?nbsp;105789 ?nbsp;005789 {徏立烦引?nbsp;Oracle 数据放在烦引中之前Q将?nbsp;把所存储数据的字节反转,q样原来可能在烦引中盔R攄的值在字节反{之后׃相距很远。通过反{字节Q对索引的插入就会分布到多个块上?/font> 位图索引Q?nbsp;bitmap index Q?/font> 在一?nbsp;B* 树中Q通常索引条目和行之间存在一U一对一的关p:一?nbsp;索引条目指向一行?/font>而对于位囄引,一个烦引条目则使用一个位囑时指向多行。位囄引适用于高度重复而且通常只读的数据(高度重复是指相对于表中的总行敎ͼ数据只有很少的几个不同|。考虑在一 个有 100 万行的表中,每个列只?nbsp;3 个可取| Y ?nbsp;N ?nbsp;NULL 。D例来_如果你需要频J地l计多少行有?/font>Y Q这很适合建立位图索引。不qƈ不是说如果这个表中某一列有 11.000 个不同的值就不能建立位图索引Q这一列当然也可以建立 位图索引。在一?nbsp;OLTP 数据库中Q由于存?/font>q发?/span>相关的问题,所以不能考虑使用位图索引Q后面我们就会讨一点)。注意,位图索引要求使用 Oracle 企业版或个h版?/font> 位图联结索引Q?nbsp;bitmap join index Q:qؓ索引l构Q而不是表Q中的数据提供了一U逆规范化?nbsp;Ҏ。例如,误虑单的 EMP ?nbsp;DEPT 表。有人可能会问这样一个问题: “ 多少人在位于波士的部门工作 Q?/font>“ EMP 有一个指?nbsp;DEPT 的外键,要想l计 LOC gؓ Boston 的部门中的员工h敎ͼ通常必须完成表联l,?nbsp;LOC 列联l至 EMP 记录来回{这个问题。通过使用位图联结索引Q则可以?nbsp;EMP 表上?nbsp;LOC 列徏立烦?nbsp;?/font> Z函数的烦引( function-based index Q?/font> q些是 B* 树烦引或位图索引Q它一个函数计得到的l果存储在行的列中,而不是存储列数据本n。可以把Z函数的烦引看作一个虚拟列Q或z列)上的索引Q换句话_q个列ƈ不物理存储在表中。基于函数的索引可以用于加快形如 SELECT * FROM T W HERE FUNCTION(DATABASE_COLUMN) = SAME_VALUE q样的查询,因ؓ?nbsp;FUNCTION(DATABASE_COLUMN) 已经提前计算q存储在索引中?/font> 应用域烦引( application domain index Q?/font> 应用域烦引是你自己构建和存储的烦引,可能存储?font face="Times New Roman">Oracle 中,也可能在 Oracle 之外。你要告诉优化器索引的选择性如何,以及执行的开销有多大,优化器则会根据你提供的信息来军_是否使用你的索引?nbsp;Oracle 文本索引是应用域烦引的一个例子;你也?nbsp;以用构?nbsp;Oracle 文本索引所用的工具来徏立自q索引。需要指出,q里创徏?nbsp;“ 索引 “ 不需要用传l的索引l构。例如, Oracle 文本索引׃用了一l表来实现其索引概念?/font> 在对数据库进行操作过E中我们可能会遇到这U情况,表中的数据可能重复出玎ͼ使我们对数据库的操作q程中带来很多的不便Q那么怎么删除q些重复没有用的数据?font face="Times New Roman">? 重复数据删除技术可以提供更大的备䆾定wQ实现更长时间的数据保留Q还能实现备份数据的持箋验证Q提高数据恢复服务水qI方便实现数据容灾{?nbsp;重复的数据可能有q样两种情况Q第一U时表中只有某些字段一PW二U是两行记录完全一栗?font face="Times New Roman">Oracle数据库重复数据删除技术有如下优势Q更大的备䆾定w、数据能得到持箋验证、有更高的数据恢复服务水q뀁方便实现备份数据的容灾?/font> 一、删除部分字D重复数?/span> 先来谈谈如何查询重复的数据吧?/span> 下面语句可以查询出那些数据是重复的: select 字段1,字段2,count(*) from 表名 group by 字段1,字段2 having count(*) > 1 上面的>h?/font>=号就可以查询出没有重复的数据了?/font> 惌删除q些重复的数据,可以使用下面语句q行删除 delete from 表名 a where 字段1,字段2 in (select 字段1,字段2,count(*) from 表名 group by 字段1,字段2 having count(*) > 1) 上面的语句非常简单,是查询到的数据删除掉。不q这U删除执行的效率非常低,对于大数据量来说Q可能会数据库吊死。所以我先将查询到的重复的数据插入到一个时表中,然后对进行删除,q样Q执行删除的时候就不用再进行一ơ查询了。如下: CREATE TABLE 临时?nbsp;AS (select 字段1,字段2,count(*) from 表名 group by 字段1,字段2 having count(*) > 1) 上面q句话就是徏立了临时表,q将查询到的数据插入其中?/span> 下面可以进行这L删除操作了: delete from 表名 a where 字段1,字段2 in (select 字段1Q字D?/font>2 from 临时?/font>); q种先徏临时表再q行删除的操作要比直接用一条语句进行删除要高效得多?/span> q个时候,大家可能会蟩出来_什?font face="Times New Roman">?你叫我们执行q种语句Q那不是把所有重复的全都删除?/font>?而我们想保留重复数据中最新的一条记录啊!大家不要急,下面我就讲一下如何进行这U操作?/font> ?font face="Times New Roman">oracle中,有个隐藏了自?/font>rowidQ里面给每条记录一个唯一?/font>rowidQ我们如果想保留最新的一条记录, 我们可以利用这个字D,保留重复数据?font face="Times New Roman">rowid最大的一条记录就可以了?/font> 下面是查询重复数据的一个例子: select a.rowid,a.* from 表名 a where a.rowid != ( select max(b.rowid) from 表名 b where a.字段1 = b.字段1 and a.字段2 = b.字段2 ) 下面我就来讲解一下,上面括号中的语句是查询出重复数据?font face="Times New Roman">rowid最大的一条记录?/font> 而外面就是查询出除了rowid最大之外的其他重复的数据了?/font> 由此Q我们要删除重复数据Q只保留最新的一条数据,可以这样写了: delete from 表名 a where a.rowid != ( select max(b.rowid) from 表名 b where a.字段1 = b.字段1 and a.字段2 = b.字段2 ) 随便说一下,上面语句的执行效率是很低的,可以考虑建立临时表,讲需要判断重复的字段?font face="Times New Roman">rowid插入临时表中Q然后删除的时候在q行比较?/font> create table 临时?nbsp;as select a.字段1,a.字段2,MAX(a.ROWID) dataid from 正式?nbsp;a GROUP BY a.字段1,a.字段2; delete from 表名 a where a.rowid != ( select b.dataid from 临时?nbsp;b where a.字段1 = b.字段1 and a.字段2 = b.字段2 ); commit; 二、完全删除重复记?/span> 对于表中两行记录完全一L情况Q可以用下面语句获取到去掉重复数据后的记录: select distinct * from 表名 可以查询的记录攑ֈ临时表中Q然后再原来的表记录删除,最后将临时表的数据导回原来的表中。如下: CREATE TABLE 临时?nbsp;AS (select distinct * from 表名); truncate table 正式?/font>; --注:原先׃W误写成?/font>drop table 正式?/font>;Q现在已l改正过?/font> insert into 正式?nbsp;(select * from 临时?/font>); drop table 临时?/font>; 如果惛_除一个表的重复数据,可以先徏一个时表Q将L重复数据后的数据导入C时表Q然后在从时表数据导入正式表?/span>Q如下: INSERT INTO t_table_bak select distinct * from t_table; 三、怎样快速删?font face="Times New Roman">oracle数据?/font> 最快的Ҏp入注册表 在运?font face="Times New Roman">..里输?/font>regedit. 依次展开HKEY_LOCAL_MACHINE SOFTWARE 扑ֈORACLE节点。删除?/font> 然后删除ORACLE数据文gQ安装的时候选的路径?/font> 最后删?font face="Times New Roman">oracle引导文gQ在pȝ盘符?/font>Program Files 里面删除oracle文g夏V?/font>
]]>
]]>
]]>
]]>
Oracle 提供了多U不同类型的索引以供使用。简单地_ Oracle 中包括如下烦引:
]]>
Q{自http://www.searchdatabase.com.cn/showcontent_23769.htmQ?/div>
]]>
ops$tkyte@ORA10GR1> create table t1
2 ( x int primary key,
3 y varchar2(25),
4 z date
5 )
6 organization index;
Table created.
使用一下方法查看详l定义语句:
ops$tkyte@ORA10GR1> select dbms_metadata.get_ddl( 'TABLE', 'T1' ) from dual;
S_METADATA.GET_DDL('TABLE','T1')
-----------------------------------------------------------------------------
CREATE TABLE "OPS$TKYTE"."T1"
(
"X" NUMBER(*,0),
"Y" VARCHAR2(25),
"Z" DATE,
PRIMARY KEY ("X") ENABLE
)
ORGANIZATION INDEX
NOCOMPRESS
PCTFREE 10 INITRANS 2 MAXTRANS 255 LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
PCTTHRESHOLD 50
在此基础上可以进行修攏V?/span>
注意Q?font face="Courier New">select dbms_metadata.get_ddl( 'TABLE', 'T1' ) from dual;?/font>“ 'TABLE', 'T1'”均要大写Q?/font>
索引l织?index organized table, IOT)是存储在一个烦引结构中的表。存储在堆中的表是无l织?也就是说Q只要有可用的空_数据可以攑֜M地方)QIOT中的数据则按主键存储和排序。对你的应用来说QIOT表和一?#8220;常规”表ƈ无二致?/span>
索引l织表的数据按主键排序手D被存储在B-树烦引中Q?/span>除了存储主键列值外q存储非键列的倹{普通烦引只存储索引列,而烦引组l表则存储表的所有列的?/span>?/span>
索引l织表一般适应于静态表Q且查询多以主键列。当表的大部分列当作主键列时Q且表相寚w态,比较适合创徏索引l织表!Q?i以上Q?/span>
既然它属于表Q那么它当然也有建立索引的需求。由于它的烦引的l构Q比如说׃索引叶节点的分裂Q行所在块可能会发生改变,因而徏立在IOT上的索引和一般的索引的最大区别是它存的是IOT的行的逻辑地址Q也是UROWIDQoracle用这个逻辑rowid来猜q个行所在的块,如果猜到了,那么q个urowid是正的Q否则它从这个地址向下遍历来找q条记录?/span>
IOT表的rowid是逻辑上的Q因为IOT表中的行的位|是在不断变化的(例如插入新的行,有可能带来其它行的位|移?
IOT有什么意义呢Q用堆l织表时Q我们必Mؓ表和表主键上的烦引分别留出空间。?/span>IOT不存在主键的I间开销Q因为烦引就是数据,数据是索引Q二者已l合二ؓ一。但是,IOT带来的好处ƈ不止于节U了盘I间的占用,更重要的是大q度降低了I/O,减少了访问缓冲区~存(管从缓冲区~存获取数据比从盘读要快得多,但缓冲区~存q不免费Q而且也绝对不是廉L。每个缓冲区~存获取都需要缓冲区~存的多个闩Q而闩是串行化讑֤Q会限制应用的扩展能?
IOT适用的场合有Q?/span>
1、完全由主键l成的表。这L表如果采用堆l织表,?/span>表本w完全是多余的开销Q因为所有的数据全部同样也保存在索引里,此时Q堆表是没用的?/span>
2、代码查找表。如果你只会通过一个主键来讉K一个表Q这个表非帔R合实现为IOT.
3、如果你想保证数据存储在某个位置上,或者希望数据以某种特定的顺序物理存储,IOT是一U合适的l构?/span>
IOT提供如下的好处: 如果l常在一个主键或惟一键上使用BETWEEN 查询也是如此Q因为相q的记录存在一P查询时引入的逻辑IO和物?/font>IO都会更少?br />
索引l织表的详细参数 ops$tkyte@ORA10GR1> select dbms_metadata.get_ddl( 'TABLE', 'T1' ) from dual; S_METADATA.GET_DDL('TABLE','T1') ----------------------------------------------------------------------------- CREATE TABLE "OPS$TKYTE"."T1" "X" NUMBER(*,0), "Y" VARCHAR2(25), "Z" DATE, PRIMARY KEY ("X") ENABLE ANIZATION INDEX OMPRESS PCTFREE 10 INITRANS 2 MAXTRANS 255 LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" PCTTHRESHOLD 50 NOCOMPRESS 选项 q个选项对烦引一般都可用。它告诉 Oracle 把每个值分别存储在各个索引条目中(也就是不压羃Q。如果对象的主键?nbsp;A?/font>B ?nbsp;C 列上Q?nbsp;A?/font>B ?nbsp;C 的每一ơ出现都会物理地存储?nbsp;NOCOMPRESS 反过来就?nbsp;COMPRESS N Q?span style="color: red">在此 N 是一个整敎ͼ表示要压~的列数。这样可以避免重复|q在块提取 “公因?#8221;Q?nbsp;factor out Q。这样在 A 的|以及 B 的|重复出现Ӟ不再物理地存储它们?/font>
·提高~冲区缓存效率,因ؓl定查询在缓存中需要的块更?/span>
·减少~冲区缓存访问,q会改善可扩~性?/span>
·获取数据的工作总量更少Q因取数据更快?/span>
·每个查询完成的物理I/O更少Q?span style="font-size: 10.5pt; font-family: 'SimSun'; mso-spacerun: 'yes'">因ؓ对于Ml定的查询,需要的块更,而且对地址记录的一个物?nbsp;I/O 很可能可以获取所有地址Q而不只是其中一个地址Q但堆表实现只是获取一个地址Q?/p>
下面做一个快速的试Q对前面 CREATE TABLE ?nbsp;SELECT 分别采用 NOCOMPRESS ?nbsp;COMPRESS 1 ?/font>COMPRESS 2 选项Q来展示能节省多空间。先来创?nbsp;IOT Q但不进行压~:
ops$tkyte@ORA10GR1> create table iot
2 ( owner, object_type, object_name,
3 constraint iot_pk primary key(owner,object_type,object_name)
4 )
5 organization index
6 NOCOMPRESS
7 as
8 select distinct owner, object_type, object_name
9 from all_objects
10 /
tablle created.
现在可以量所用的I间。ؓ此我们将使用 ANALYZE INDEX VALIDATE STRUCTURE 命o?span style="color: red">q个命o会填写一个名?nbsp;INDEX_STATS 的动态性能视图Q其中最多只包含一行,卌?nbsp;ANALYZE 命o最后一ơ执行的信息Q?/font>
ops$tkyte@ORA10GR1> analyze index iot_pk validate structure;
index analyzed.
ops$tkyte@ORA10GR1> select lf_blks, br_blks, used_space,
2 opt_cmpr_count, opt_cmpr_pctsave
3 from index_stats;
LF_BLKS BR_BLKS USED_SPACE OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
284 3 2037248 2 33
由此昄出,我们的烦引目前用了 284 个叶子块Q即数据所在的块)Qƈ使用?nbsp;3 个分支块Q?nbsp;Oracle在烦引结构中D所用的块)来找到这些叶子块。用的I间大约?nbsp;2MB Q?/font>2,038,248 字节Q。另外两列名字有些奇怪,q两列是要告诉我们一些信息?nbsp;OPT_CMPR_COUNT Q最优压~数Q列要说的是Q?#8220; 如果你把q个索引|ؓ COMPRESS 2 Q就会得到最佳的压羃 ” ?nbsp;OPT_CMPR_PCTSAVE Q最优的节省压羃癑ֈ比)则是?nbsp;Q?/font>如果执行 COMPRESS 2 Q就能节省大U?nbsp;1/3 的存储空_索引只会使用现在 2 /3 的磁盘空间?br />
下面?font face="Times New Roman">COMPRESS 2q行压羃Q?/font>
ops$tkyte@ORA10GR1> alter table iot move compress 2;
ops$tkyte@ORA10GR1> analyze index iot_pk validate structure;
Index analyzed.
ops$tkyte@ORA10GR1> select lf_blks, br_blks, used_space,
2 opt_cmpr_count, opt_cmpr_pctsave
3 from index_stats;
LF_BLKS BR_BLKS USED_SPACE OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
190 1 1359357 2 0
现在大小有了显著减少Q不论是叶子块数q是ȝ使用I间都大q下降?br /> Q关于这个参数的详细说明参见W十一?索引 11.2.1?索引键压~?Q?br />
OVERFLOW&PCTTHRESHOLD&INCLUDING选项
OVERFLOW 子句允许你徏立另一个段Q这׃?nbsp;IOT 成ؓ一个多D对象,像有一?nbsp;CLOB 列一PQ如?nbsp;IOT 的行数据变得太大Q就可以溢出到这个段中?/font>
注意Q构成主键的列不能溢出,它们必须直接攑֜叶子块上?/span>
PCTTHRESHOLD Q行中的数据量超q块的这个百分比Ӟ行中余下的列存储在溢出D中。所以,如果 PCTTHRESHOLD ?nbsp;10% Q而块大小?nbsp;8KB Q长度大?nbsp;800 字节的行׃把其中一部分存储在别处,而不能在索引块上存储?/font>
INCLUDING Q行中从W一列直?nbsp;INCLUDING 子句所指定列(也包括这一列)的所有列都存储在索引块上Q余下的列存储在溢出D中?/font>
对于 IOT 最后要考虑的是建立索引?nbsp;IOT 本n可以有一个烦引,像在烦引之上再加烦引,q称Zơ烦引( secondary index Q?nbsp;正常情况下,索引包含了所指向的行的物理地址Q即 rowid 。?nbsp;IOT 二次索引无法做到q一点;它必M用另外某U方法来指示行的地址。这是因?nbsp;IOT ?nbsp;的行可以大量UdQ?nbsp;而且它不像堆l织表中的行那样 “ q移 ” ?nbsp;IOT 中的行肯定在索引l构中的每个位置上,q取决于它的主键|只有当烦引本w的大小和Ş?nbsp;发生改变时行才会UdQ下一章将更详l地讨论索引l构如何l护Q?/font>
Z适应q种情况Q?nbsp;O racle 引入了一个逻辑 rowid Q?nbsp;logical rowid Q?nbsp;q些逻辑 rowid Ҏ IOT 主键建立。对于行的当前位|还可以包含一?nbsp;“ 猜测 ” Q不q这个猜几乎是错的Q因为稍q一D|间后Q?nbsp;IOT中的数据可能׃ Ud。这个猜是行第一ơ置于二ơ烦引结构中时在 IOT 中的物理地址。如?nbsp;IOT ?nbsp;的行必须Ud到另外一个块上,二次索引中的猜测׃变得 “ q时 ” 。因 此,与常规表相比Q?nbsp;IOT 上的?nbsp;引效率稍低。在一个常规表上,索引讉K通常需要完成一?nbsp;I/O 来扫描烦引结构,然后需要一个读来读取表数据。对?nbsp;IOT Q?nbsp;通常?nbsp;完成两个扫描Q一ơ扫描二ơ结构,另一ơ扫?nbsp;IOT 本n。除此之外, IOT 上的索引可以使用非主键列提供 IOT 数据的快速、高效访问?br />
索引l织表小l?/strong>
?nbsp;建立 IOT Ӟ最关键的是适当地分配数据,卛_些数据存储在索引块上Q哪些数据存储在溢出D上。对溢出条g不同的各U场景进行基准测试,查看?nbsp;INSERT ?nbsp;UPDATE ?nbsp;DELETE ?nbsp;SELECT 分别有怎样的媄响。如果结构只建立一ơ,而且要频J读取,应该尽可能地把数据攑֜索引块上Q最合适获取)Q要么频J地l织索引中的数据Q不适于修改Q。堆表的 freelist 相关考虑?nbsp;IOT 也同样适用?nbsp;PCTFREE ?/font>PCTUSED ?nbsp;IOT ?nbsp;是两个重要的角色。不q, PCTFREE 对于 IOT 不像对于堆表那么重要Q另?nbsp;PC TUSED 一般不起作用。不q,考虑 OVERFLOW D|Q?nbsp;PCTFREE ?nbsp;PCTUSED 对于 IOT 的意义将与对于堆表一样重大;要采用与堆表相同的逻辑为溢出段讄q两个参数?/font>
不同?
1. truncate?delete只删除数据不删除表的l构(定义)
drop语句删除表的结构被依赖的约?constrain),触发?trigger),索引(index); 依赖于该表的存储q程/函数保?但是变ؓinvalid状?
2.delete语句是dml,q个操作会放到rollback segement?事务提交之后才生?如果有相应的trigger,执行的时候将被触?
truncate,drop是ddl, 操作立即生效,原数据不攑ֈrollback segment?不能回滚. 操作不触发trigger.
3.delete语句不媄响表所占用的extent, 高水U?high watermark)保持原位|不?
昄drop语句表所占用的空间全部释?
truncate 语句~省情况下见I间释放?minextents?extent,除非使用reuse storage; truncate会将高水U复?回到最开?.
4.速度,一般来? drop>; truncate >; delete
5.安全?心使用drop 和truncate,其没有备䆾的时?否则哭都来不?nbsp;
使用?惛_除部分数据行用delete,注意带上where子句. 回滚D要_?
惛_除表,当然用drop
想保留表而将所有数据删? 如果和事务无?用truncate卛_. 如果和事务有?或者想触发trigger,q是用delete.
如果是整理表内部的碎?可以用truncate跟上reuse stroage,再重新导?插入数据
TRUNCATE TABLE 在功能上与不?nbsp; WHERE 子句?nbsp; DELETE 语句相同Q二者均删除表中的全部行。但 TRUNCATE TABLE ?nbsp; DELETE 速度快,且用的pȝ和事务日志资源少?nbsp;
DELETE 语句每次删除一行,q在事务日志中ؓ所删除的每行记录一VTRUNCATE TABLE 通过释放存储表数据所用的数据|删除数据Qƈ且只在事务日志中记录늚释放?nbsp;
TRUNCATE TABLE 删除表中的所有行Q但表结构及其列、约束、烦引等保持不变。新行标识所用的计数值重|ؓ该列的种子。如果想保留标识计数|h?nbsp; DELETE。如果要删除表定义及其数据,请?nbsp; DROP TABLE 语句?nbsp;
对于?nbsp; FOREIGN KEY U束引用的表Q不能?nbsp; TRUNCATE TABLEQ而应使用不带 WHERE 子句?nbsp; DELETE 语句。由?nbsp; TRUNCATE TABLE 不记录在日志中,所以它不能Ȁz触发器?nbsp;
TRUNCATE TABLE 不能用于参与了烦引视囄表?/p>
1.使用版本?/strong>
附加一个LAST_MODIFIED列,cd可以?timestamp with time zone default systemstampQora 9i以上Q?q个cd在Oracle中精度最高,_到百万分之一U?br />
不徏议用触发器Q因为开销太大Q而由DML来负责?/span>
2.使用校验和的乐观锁定
使用一个虚拟的版本列来判断数据是否改变?br />
与用版本列的做法一P我们可以采用同样的方法用这些散列值或校验和,只需把从数据库读出数据时得到的散列或校验和g修改数据前得到的散列或校验和D行比较。在我们d数据之后Q?但是在修Ҏ据之前,如果有h在这D|间内修改了这一行的|散列值或校验和值往往会大不相同?br />
以下为Oracle提供的三U计散列值得数据包:
OWA_OPT_LOCK.CHECKSUM Q这个方法在 Oracle8i 8.1.5 及以上版本中提供。给定一个串Q其中一个函Cq回一?16 位的校验和。给?ROWID Ӟ另一个函C计算该行?16 位校验和Q而且同时这一行锁定。出现冲H的可能性是 65 536 分之一Q?65 536 个串中有一个冲H,q是假警报的最大几率)?br />
DBMS_OBFUSCATION_TOOLKIT.MD5 Q这个方法在 Oracle8i 8.1.7 及以上版本中提供。它会计一?128 位的消息摘要。冲H的可能性是 3.4028E+38 分之一Q非常小Q?br />
DBMS_CRYPTO.HASH Q这个方法在 Oracle 10g Release 1 及以上版本中提供。它能计一个SHA-1 Q安全散列算?1 Q?Secure Hash Algorithm 1 Q或 MD4/MD5 消息摘要。徏议你使用 SHA- 1法?br />
注意 很多~程语言中都提供了一些散列和校验和函敎ͼ所以还可以使用数据库之外的散列和校验和函数?br />
要记住,计算散列或校验和是一?CPU 密集型操?/span>Q相当占?CPU Q,其计代价很昂贵。如果系l上 CPU 是稀有资源,在这U系l上必d分考虑到这一炏V不q,如果?“ |络友好?” 角度看,q种Ҏ会比较好Q因为只需在网l上传输相当的散列|而不是行的完整的前映像和后映像(以便逐列地进行比较)Q所以消耗的资源会少得多。下面会使用一个新?Oracle 10g 函数 ORA_ROWSCN Q它不仅很小Q类g散列Q,而且计算时不?CPU 密集的(不会q多占用 CP U Q?br />
3.使用ORA_ROWSCN
ORA_ROWSCN 建立在内?Oracle pȝ旉Q?SCN Q基上。在 Oracle 中,每次提交Ӟ SCN 都会推进Q其他情况也可能D SCN 推进Q要注意Q?SCN 只会推进Q绝对不会后退Q。这个概念与前面在获取数?时得?ORA_ROWSCN 的方法是一LQ更新数据时要验?SCN 未修改过。之所以我会强调这一点(而不是草草带q)Q原因是除非你创时支持在行lORA_ROWSCN Q否?Oracle 会在块l护?span style="color: red">也就是说Q默认情况下Q一个块上的多行会共享相同的 ORA_ROWSCN 倹{?/span>如果更新一个块上的某一行,而且 q个块上q有另外 50 行,那么q些行的 ORA_ROWSCN 也会推进。这往往会导致许多假警报Q你认ؓ某一行已l修改,但实际上它ƈ没有改动。因此,需要注意这一点,q了解如何改变这U行为?br />
要修改这个特性,只能重新建立表,q启?ROWDEPENDENCIES ?br />
使用乐观锁定q是悲观锁定Q?/strong>
那么哪种Ҏ最好呢Q根据我的经验,悲观锁定?/span> Oracle 中工作得非常好(但是在其他数据库中可能不是这PQ而且与乐观锁定相比,悲观锁定有很多优炏V不q,它需要与数据库有一条有状态的q接Q如客户 / 服务器连接,因ؓ无法跨连接持有锁。正是因一点,在当前的许多情况下,悲观锁定不太现实。过去,客户 / 服务器应用可能只有数十个或数百个用户Q对于这些应用,悲观锁定是我的不二选择。不q,如今对大多数应用来说Q我都徏议采用乐观ƈ发控制。要在整个事务期间保持连接,q个代h太大了,一般无法承受?/span>
在这些可用的Ҏ中,我用哪一U呢Q我喜欢使用版本列方法,q增加一个时间戳?/span>Q而不只是一?/span> NUMBER Q。从长远看,q样能ؓ我提供一个额外的信息Q?/span> “ q一行最后一ơ更新发生在什么时_ ” 所以意义更大。而且与散列或校验和方法相比,计算的代价不那么昂贵Q在处理 LONG ?/span> LONG RAW ?/span> CLOB ?/span> BLO B和其他非常大的列Ӟ散列或校验和Ҏ可能会遇C些问题,而版本列Ҏ则没有这些问题?/span>
如果必须向一个表增加乐观q发控制Q而此时还在利用悲观锁定机制用这个表Q例如,客户 / 服务器应用都在访问这个表Q而且q在通过 Web 讉KQ,我则們于选择 ORA_ROWSCN Ҏ。这是因为,在现有的遗留应用中,可能不希望出C个新列,或者即使我们另外增加一步把q个额外的列隐藏hQ用散列等{方式)Qؓ了维护这个列Q可能需要一个必要的触发器,而这个触发器的开销非常大,q是我们无法承受的?/span> ORA_ROWSCN技术没有干扰性,而且在这个方面是轻量U的Q当Ӟq是指我们执行表的重Z后)?/span>
散列 / 校验和方法在数据库独立性方面很不错Q特别是如果我们在数据库之外计算散列或校验和Q则更是如此。不q,如果在中间层而不是在数据库中执行计算Q从 CPU 使用和网l传输方面来看,׃带来更大的资源用开销?/span>
如果只是L据, Oracle l不会对数据锁定。不会因为简单的L作在数据行上锁定?/span>
写入器( writer Q不会阻塞读取器Q?span lang="EN-US"> reader Q。换U说法:读( read Q不会被写( write Q?d?/span>q一点几乎与其他所有数据库都不一栗在其他数据库中Q读往往会被写阻塞。尽听上去q个Ҏ似乎很不错Q一般情况下实如此Q,但是Q如果你没有充分理解q个思想Q而且想通过应用逻辑对应用施加完整性约束,极有可能做得不寏V?/span>
写入器想写某行数据,但另一个写入器已经锁定了这行数据,此时该写入器才会被阻塞?d器绝对不会阻塞写入器?
卻IL不会d读,也不会阻塞写Q写不会d读,但会d写?br />
Oracle 的无dҎ有一个副作用Q如果确实想保证一ơ最多只有一个用戯问一行数据,开发h员就得自己做些工作。要加入我们自己的串行化机制来确保业务逻辑的正性,如for update语句会L作也对相应的行加锁,保了串行访问?br />
4. Oracle多版?br />
①、Oracle多版本特性是Oracleq发控制机制的基Q?Oracle 采用了一U多版本、读一_ read-consistent Q的q发模型。实质上Ԍ Oracle 利用q种机制提供了以下特性:
M致查询:对于一个时间点Q?point in time Q,查询会生一致的l果?br />
非阻塞查询:查询不会被写入器dQ但在其他数据库中可能不是这栗?br />
②、由于有多版本机ӞOracle中没?#8220;׃n?#8221;锁的概念?br />
只要你修Ҏ据, Oracle ׃创徏撤销Q?undo Q条目。这?undo 条目写至 undo D(撤销D, undo segment Q。如果事务失败,需要撤销Q?Oracle ׃从这个回滚段d “ 之前 ” 的映像,q恢复数据。除了用回滚段数据撤销事务外, Oracle q会用它撤销d块时对块所做的修改Q之恢复到查询开始前的时间点 。这样就能摆脱锁来得C致、正的{案Q而无需你自己对M数据锁定?br />
Oracle非阻塞读是这样实现的Q?Oracle 只看数据是否改变Q它q不兛_数据当前是否锁定Q锁定意味着数据已经改变Q?Oracle 只是从回滚段中取回原来的|ql处理下一个数据块?br />
在数据库中,可以得到同一个信息处于不同时间点的多个版本。Oracle 能充分用不同时间点的数据快照来提供M致查询和非阻塞查询?br />
5.在SQL Server和Sybase中,NULLq于NULLQ但是,在Oracle中,NULL与NULL既不相等Q也不完全不相等?br />
6.Oracle没有“׃n?#8221;锁?br />
Q?/span> 2 Q作?/span> SYSTEM d SQL*Plus Q?/span>
Q?/span> 3 Q运?/span> @utlxplan Q?/span>
Q?/span> 4 Q运?/span> CREATE PUBLIC SYNONYM PLAN_TABLE FOR PLAN_TABLE Q?/span>
Q?/span> 5 Q运?/span> GRANT ALL ON PLAN_TABLE TO PUBLIC ?/span>
可以?/span> GRANT TO PUBLIC 中的 PUBLIC 替换为某个用戗通过?/span> PLAN_TABLE |ؓ public QQ何h都可以?/span> SQL*Plus q行跟踪。这么一来,׃需要每个用户都安装自己的计划表。还有一U做法是Q在惌使用 AUTOTRACE 的每个模式中分别q行 @utlxplan ?/span>
下一步是创徏q授?/span> PLUSTRACE 角色Q?/span>
Q?/span> 1 Q?/span> cd [ORACLE_HOME]/sqlplus/admin Q?/span>
Q?/span> 2 Q作?/span> SYS ?/span> SYSDBA d SQL*Plus Q?/span>
Q?/span> 3 Q运?/span> @plustrce Q?/span>
Q?/span> 4 Q运?/span> GRANT PLUSTRACE TO PUBLIC ?/span>
通过讄 AUTOTRACE pȝ变量可以控制q个报告Q?/span>
?SET AUTOTRACE OFF Q不生成 AUTOTRACE 报告Q这是默认设|?/span>
?SET AUTOTRACE ON EXPLAIN Q?/span> AUTOTRACE 报告只显CZ化器执行路径?/span>
?SET AUTOTRACE ON STATISTICS Q?/span> AUTOTRACE 报告只显C?/span> SQL 语句的执行统计信息?/span>
?SET AUTOTRACE ON Q?/span> AUTOTRACE 报告既包括优化器执行路径Q又包括 SQL 语句的执行统计信息?/span>
?SET AUTOTRACE TRACEONLY Q这?/span> SET AUTOTRACE ON cMQ但是不昄用户的查询输出(如果有的话)?/span>