几天前okrrrr发音2还登过的站,怎么今天wwWokrrrr发音2com就变为空白了

作者QQ 交流群 祝大家学习进步。
如果大家想看Word版本的可以去下载:Word排版比较清晰一些。

此笔记是作者本人去年开始从一个DBA新人的学习笔记,积累至今,希望拿出来给那些对DBA有兴趣的童孩学习,大家一起努力嘛。
此笔记记录了作者工作学习中从零基础的学习的记录,和从中遇见的问题与问题的解决!很高兴大家来疯狂源代码大家庭交流学习!
感谢支持,鞠躬!!转载请注明作者哦!!谢谢。
此文章不断更新!!谢谢大家支持!!

*DQL:数据查询语言
*DML:数据操作语言
*DDL:数据定义语言

5、使用$后面跟window命令符可以使用window命令

–设置绑定变量使用占位符

PL/SQL 过程已成功完成。 dbms_'); --这行没有输出是因为没有换行!

–示例四、为字符串的前后都加上单引号

–示例五、为字符串的前后都加上双引号,并且变为大写

–示例六、验证字符串是否为有效模式对象名

–示例七、输入错误的械对象

–示例八、验证字符串是否为有效模式名

–实例九,输入错误模式名

–系统自带工具包DBMS.JOB包

–查询当前用户所有job

–修改执行间隔,在cmd执行

–删除当前job,在cmd执行

DBMS_LOB包提供了对大对象的操作支持,用户可以直接利用此包的实现对CLOB(大文本)或者BLOB(二进制数据例如:图片,音乐,文字等)类型的列进行操作

 1、复制目录的时候可能在盘符后面有乱码;
 3、目录的名字一定要和创建名字大小写相同,这里是区分大小写的!

  其实,我前面一篇讲表空间的时候就介绍了数据库的结构,只是那个图只是简单的层次关系,这张图片看上去挺封复杂的,只要关注几个概念就行了。
Database(数据库) :数据库是按照数据结构来组织、存储和管理数据的仓库。
Tablespaces(表空间) :表空间是数据库的逻辑划分,一个表空间只能属于一个数据库。所有的数据库对象都存放在指定的表空间中。但主要存放的对象是表, 所以称作表空间。
Segments (段): 段是表空间的重要组织结构,段是指占用数据文件空间的通称,或数据库对象使用的空间的集合;段可以有表段、索引段、回滚段、临时段和高速缓存段等。
extents (盘区):是数据库存储空间分配的一个逻辑单位,它由连续数据块所组成。第一个段是由一个或多个盘区组成。当一段中间所有空间已完全使用,oracle为该段分配一个新的范围。
Data Block (数据块):是oralce 管理数据文件中存储空间的单位,为数据库使用的I/O的最小单位,其大小可不同于操作系统的标准I/O块大小。

如果要执行完全导出,必须具有特殊的权限 这样用户SONIC的所有对象被输出到文件中。

具有三种模式(完全、用户、表)

这样用户SONIC的所有对象被导入到文件中。必须指定FROMUSER、TOUSER参数,这样才能导入数据。 这样用户SONIC的表SONIC就被导入。

–只导出3张表的结构:

–导出带数据的表(owner和tables不能同时使用)


数据泵导出的各种模式:

2、按用户导入(可以将用户信息直接导入,即如果用户信息不存在的情况下也可以直接导入)

3、不通过expdp的步骤生成dmp文件而直接导入的方法:

igisdb是目的数据库与源数据的链接名,dir_dp是目的数据库上的目录

–导出gwm用户下的所有数据

注:如果是用sys用户导出的用户数据,包括用户创建、授权部分,用自身用户导出则不含这些内容
–以下是将gwm用户下的数据全部导入到表空间gcomm(原来为gmapdata表空间下)下




数据泵导入实用程序提供了一种用于在 Oracle 数据库之间传输
数据对象的机制。该实用程序可以使用以下命令进行调用:

您可以控制导入的运行方式。具体方法是: 在 ‘impdp’ 命令后输入各种参数。要指定各参数, 请使用关键字:

USERID 必须是命令行中的第一个参数。

关键字 说明 (默认)
DIRECTORY 供转储文件,日志文件和sql文件使用的目录对象。
ENCRYPTION_PASSWORD 用于访问加密列数据的口令关键字。此参数对网络导入作业无效。
FULL 从源导入全部对象(Y)。
JOB_NAME 要创建的导入作业的名称。
NETWORK_LINK 链接到源系统的远程数据库的名称。
QUERY 用于导入表的子集的谓词子句。
REMAP_SCHEMA 将一个方案中的对象加载到另一个方案。
REMAP_TABLESPACE 将表空间对象重新映射到另一个表空间。
SCHEMAS 要导入的方案的列表。
STATUS 在默认值(0)将显示可用时的新状态的情况下,要监视的频率(以秒计)作业状态。
TABLES 标识要导入的表的列表。
TABLESPACES 标识要导入的表空间的列表。

下列命令在交互模式下有效。

CONTINUE_CLIENT 返回到记录模式。如果处于空闲状态, 将重新启动作业。 EXIT_CLIENT 退出客户机会话并使作业处于运行状态。 HELP 总结交互命令。


备注:红色标记的选项是比较常用的,需知晓其用法。

  众所周知:IMP工具的FROMUSER和TOUSER参数可以实现将一个用户的的数据迁移到另外一个用户。
  (1)impdp数据泵使用REMAP_SCHEMA参数来实现不同用户之间的数据迁移;

  使用PARALLEL参数可以提高数据泵还原的效率,前提是必须有多个expdp的文件,如expdp01.dmp,expdp02.dmp,expdp03dmp等等,不然会有问题。运行impdp命令时,会先启动一个WOrKER进程将METADATA导入,然后再启动多个WORKER进程将数据以及其他对象导入,所以在前期只会看到一个WOrKER在导入METADATA,而且IMPDP也需要DUMP文件是多个,也可以使用%U来进行导入。

美国国家标准学会的标准码
可以认为是不同的东西!

2、Oracle的表分析是做什么的?

分析的结果被Oracle用于基于成本的优化生成更好的查询计划。
那么,问题在于:Oracle的表分析需要经常进行吗?还是只要跑一回就可以一直有效了?

答:遇到当前表的查询或其他性能不好时,就可以对相应的表进行一次分析。1。如果你的表经常由几千万变成几百万,又变成几千万那么需要制定分析计划定期表分析,同时可以一并分析索引,计算索引中数据的分布情况,这样CBO会选择更加准确的执行计划。2。如果表结构变化了也要做下,也就是经常对表做dml就需要分析,现在推荐使用dbms_stats包。

七、Oracle行转列,列转行总结

1、这个比较简单,用||或concat函数可以实现

首先让我们来看看这个神奇的函数wm_concat(列名),该函数可以把列值以”,”号分隔起来,并显示成一行,接下来上例子,看看这个神奇的函数如何应用准备测试数据

效果1 : 行转列 ,默认逗号隔开


效果2: 把结果里的逗号替换成”|”

——– 适用范围:10g及以后版本 ( MODEL )

/* 这里的表名默认区分大小写 /

google 一下,网上有一篇比较详细的文档:
测试数据 (id,类型名称,销售数量),案例:根据水果的类型查询出一条数据显示出每种类型的销售数量。


分组查询 (当然这是不符合查询一条数据的要求的)

当然也可以不使用pivot函数,等同于下列语句,只是代码比较长,容易理解

顾名思义就是将多列转换成1列中去
案例:现在有一个水果表,记录了4个季度的销售数量,现在要将每种水果的每个季度的销售情况用多行数据展示。


同样不使用unpivot也可以实现同样的效果,只是sql语句会很长,而且执行速度效率也没有前者高

上述pivot列转行示例中,你已经知道了需要查询的类型有哪些,用in()的方式包含,假设如果您不知道都有哪些值,您怎么构建查询呢?
pivot 操作中的另一个子句 XML 可用于解决此问题。该子句允许您以 XML 格式创建执行了 pivot 操作的输出,在此输出中,您可以指定一个特殊的子句 ANY 而非文字值


如您所见,列 NAME_XML 是 XMLTYPE,其中根元素是 。每个值以名称-值元素对的形式表示。您可以使用任何 XML 分析器中的输出生成更有用的输出。


Pivot 为 SQL 语言增添了一个非常重要且实用的功能。您可以使用 pivot 函数针对任何关系表创建一个交叉表报表,而不必编写包含大量 decode 函数的令人费解的、不直观的代码。同样,您可以使用 unpivot 操作转换任何交叉表报表,以常规关系表的形式对其进行存储。Pivot 可以生成常规文本或 XML 格式的输出。如果是 XML 格式的输出,您不必指定 pivot

Oracle提供了大量索引选项。知道在给定条件下使用哪个选项对于一个应用程序的性能来说非常重要。一个错误的选择可能会引发死锁,并导致数据库性能急剧下降或进程终止。而如果做出正确的选择,则可以合理使用资源,使那些已经运行了几个小时甚至几天的进程在几分钟得以完成,这样会使您立刻成为一位英雄。这篇文章就将简单的讨论每个索引选项。主要有以下内容:

[1] 基本的索引概念

查询DBA_INDEXES视图可得到表中所有索引的列表,注意只能通过USER_INDEXES的方法来检索模式(schema)的索引。访问USER_IND_COLUMNS视图可得到一个给定表中被索引的特定列。 

 当某个索引包含有多个已索引的列时,称这个索引为组合(concatented)索引。在 Oracle9i引入跳跃式扫描的索引访问方法之前,查询只能在有限条件下使用该索引。比如:表emp有一个组合索引键,该索引包含了empno、 ename和deptno。在Oracle9i之前除非在where之句中对第一列(empno)指定一个值,否则就不能使用这个索引键进行一次范围扫描。 

特别注意:在Oracle9i之前,只有在使用到索引的前导索引时才可以使用组合索引!

通过每个行的ROWID,索引Oracle提供了访问单行数据的能力。ROWID其实就是直接指向单独行的线路图。如果想检查重复值或是其他对ROWID本身的引用,可以在任何表中使用和指定rowid列。

限制索引是一些没有经验的开发人员经常犯的错误之一。在SQL中有很多陷阱会使一些索引无法使用。下面讨论一些常见的问题:

下面的查询即使在cust_rating列有一个索引,查询语句仍然执行一次全表扫描。

把上面的语句改成如下的查询语句,这样,在采用基于规则的
优化器而不是基于代价的优化器(更智能)时,将会使用索引。

特别注意:通过把不等于操作符改成OR条件,就可以使用索引,以避免全表扫描。

使用IS NULL 或IS NOT NULL同样会限制索引的使用。因为NULL值并没有被定义。在SQL语句中使用NULL会有很多的麻烦。因此建议开发人员在建表时,把需要索引的列设成NOT NULL。如果被索引的列在某些行中存在NULL值,就不会使用这个索引(除非索引是一个位图索引,关于位图索引在稍后在详细讨论)。

如果不使用基于函数的索引,那么在SQL语句的WHERE子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。 下面的查询不会使用索引(只要它不是基于函数的索引)

把上面的语句改成下面的语句,这样就可以通过索引进行查找。

4.4 比较不匹配的数据类型
比较不匹配的数据类型也是比较难于发现的性能问题之一。
在account_number字段上有索引。下面的语句将执行全表扫描。

特别注意:不匹配的数据类型之间比较会让Oracle自动限制索引的使用,
即便对这个查询执行Explain Plan也不能让您明白为什么做了一次“全表扫描”。

使用USER_INDEXES视图,该视图中显示了一个distinct_keys列。比较一下唯一键的数量和表中的行数,就可以判断索引的选择性。选择性越高,索引返回的数据就越少。

Clustering Factor位于USER_INDEXES视图中。该列反映了数据相对于已索引的列是否显得有序。如果Clustering Factor列的值接近于索引中的树叶块(leaf block)的数目,表中的数据就越有序。如果它的值接近于表中的行数,则表中的数据就不是很有序。

索引的二元高度对把ROWID返回给用户进程时所要求的I/O量起到关键作用。在对一个索引进行分析后,可以通过查询DBA_INDEXES的B- level列查看它的二元高度。二元高度主要随着表的大小以及被索引的列中值的范围的狭窄程度而变化。索引上如果有大量被删除的行,它的二元高度也会增加。更新索引列也类似于删除操作,因为它增加了已删除键的数目。重建索引可能会降低二元高度。

在Oracle7.3后就可以使用快速全局扫描(Fast Full Scan)这个选项。这个选项允许Oracle执行一个全局索引扫描操作。快速全局扫描读取B-树索引上所有树叶块。初始化文件中的 DB_FILE_MULTIBLOCK_READ_COUNT参数可以控制同时被读取的块的数目。

从Oracle9i开始,索引跳跃式扫描特性可以允许优化器使用组合索引,即便索引的前导列没有出现在WHERE子句中。索引跳跃式扫描比全索引扫描要快的多。下面的程序清单显示出性能的差别:

适合与大量的增、删、改(OLTP);
不能用包含OR操作符的查询;
适合高基数的列(唯一值多)
大多都是物理上一层、两层或三层不定,逻辑上三层;
叶子块数据是排序的,从左向右递增;
在分支块和根块中放的是索引的范围;

做UPDATE代价非常高;
非常适合OR操作符的查询;
基数比较少的时候才能建位图索引;
开始ROWID,结束ROWID(先列出索引的最大范围)
每一个BIT对应着一个ROWID,它的值是1还是0,如果是1,表示着BIT对应的ROWID有值;

B*tree索引的话通常在访问小数据量的情况下比较适用,比如你访问不超过表中数据的5%,当然这只是个相对的比率,适用于一般的情况。bitmap的话在数据仓库中使用较多,用于低基数列,比如性别之类重复值很多的字段,基数越小越好。

  对于表而言(常规意义上的堆组织表),上述分区形式都可以应用(甚至可以对某个分区指定compress属性),只不过分区依赖列不能是lob,long之类数据类型,每个表的分区或子分区数的总数不能超过1023个。

  对于索引组织表,只能够支持普通分区方式,不支持组合分区,常规表的限制对于索引组织表同样有效,除此之外呢,还有一些其实的限制,比如要求索引组织表的分区依赖列必须是主键才可以等。

  注:本篇所有示例仅针对常规表,即堆组织表!

  对于索引,需要区分创建的是全局索引,或本地索引:

  l 全局索引(global index):即可以分区,也可以不分区。即可以建range分区,也可以建hash分区,即可建于分区表,又可创建于非分区表上,就是说,全局索引是完全独立的,因此它也需要我们更多的维护操作。

  l 本地索引(local index):其分区形式与表的分区完全相同,依赖列相同,存储属性也相同。对于本地索引,其索引分区的维护自动进行,就是说你add/drop/split/truncate表的分区时,本地索引会自动维护其索引分区。

  Oracle建议如果单个表超过2G就最好对其进行分区,对于大表创建分区的好处是显而易见的,这里不多论述why,而将重点放在when以及how。

  Range分区呢是应用范围比较广的表分区方式,它是以列的值的范围来做为分区的划分条件,
将记录存放到列值所在的range分区中,比如按照时间划分,2008年1季度的数据放到a分区,08年2季度的数据放到b分区,因此在创建的时候呢,需要你指定基于的列,以及分区的范围值,如果某些记录暂无法预测范围,可以创建maxvalue分区,所有不在指定范围内的记录都会被存储到maxvalue所在分区中,并且支持指定多列做为依赖列,后面在讲how的时候会详细谈到。

  通常呢,对于那些无法有效划分范围的表,可以使用hash分区,这样对于提高性能还是会有一定的帮助。hash分区会将表中的数据平均分配到你指定的几个分区中,列所在分区是依据分区列的hash值自动分配,因此你并不能控制也不知道哪条记录会被放到哪个分区中,hash分区也可以支持多个依赖列。

  List分区与range分区和hash分区都有类似之处,该分区与range分区类似的是也需要你指定列的值,但这又不同与range分区的范围式列值—其分区值必须明确指定,也不同与hash分区—通过明确指定分区值,你能控制记录存储在哪个分区。它的分区列只能有一个,而不能像range或者hash分区那样同时指定多个列做为分区依赖列,不过呢,它的单个分区对应值可以是多个。

  你在分区时必须确定分区列可能存在的值,一旦插入的列值不在分区范围内,则插入/更新就会失败,因此通常建议使用list分区时,要创建一个default分区存储那些不在指定范围内的记录,类似range分区中的maxvalue分区。

  四、When使用组合分区

  如果某表按照某列分区之后,仍然较大,或者是一些其它的需求,还可以通过分区内再建子分区的方式将分区再分区,即组合分区的方式。

  组合分区呢在10g中有两种:range-hash,range-list。注意顺序哟,根分区只能是range分区,子分区可以是hash分区或list分区。

  提示:11g在组合分区功能这块有所增强,又推出了range-range,list-range,list-list,list-hash,这就相当于除hash外三种分区方式的笛卡尔形式都有了。为什么会没有hash做为根分区的组合分区形式呢,再仔细回味一下第二点,你一定能够想明白~~。

Oracle数据库中,有两种类型的分区索引,全局索引和本地索引,其中本地索引又可以分为本地前缀索引和本地非前缀索引。下面就分别看看每种类型的索引各自的特点。

全局索引以整个表的数据为对象建立索引,索引分区中的索引条目既可能是基于相同的键值但是来自不同的分区,也可能是多个不同键值的组合。

全局索引既允许索引分区的键值和表分区键值相同,也可以不相同。全局索引和表之间没有直接的联系,这一点和本地索引不同。

从上面的语句可以看出,全局索引和表没有直接的关联,必须显式的指定maxvalue值。假如表中新加了分区,不会在全局索引中自动增加新的分区,必须手工添加相应的分区。



使用全局索引,索引键值必须和分区键值相同,这就是所谓的前缀索引。Oracle不支持非前缀的全局分区索引,如果需要建立非前缀分区索引,索引必须建成本地索引。

接下来再来看看本地分区。

本地索引的分区和其对应的表分区数量相等,因此每个表分区都对应着相应的索引分区。使用本地索引,不需要指定分区范围因为索引对于表而言是本地的,当本地索引创建时,Oracle会自动为表中的每个分区创建独立的索引分区。

创建本地索引不必显式的指定maxvalue值,因为为表新添加表分区时,会自动添加相应的索引分区。



这里系统已经自动以和表分区相同的名字自动创建了一个索引分区。同理,删除表分区时相对应的索引分区也自动被删除。

本地索引和全局索引还有一个显著的差别,就是上面提到的,本地索引可以创建成本地非前缀型,而全局索引只能是前缀型。


从上面的输出可以看出,虽然索引的键值是part_no,但索引分区的键值仍然和表的分区键值相同,即ord_date,也即是所谓的非前缀型索引。

最后,再引用一个例子说明前缀索引和非前缀索引的应用。

假设有一个使用DATE列分区的大表。我们经常使用一个VARCHAR2列(VCOL)进行查询,但这个列并不是表的分区键值。

有两种可能的方法来访问VCOL列的数据,一是建立基于VCOL列的本地非前缀索引,


另一种是建立基于VCOL列的全局索引,


可以看出,如果能够保证VCOL列值的唯一性,全局索引将会是最好的选择。如果VCOL列值不唯一,就需要在本地非前缀索引的并行查询和全局索引顺序查询以及高昂的维护代价之间做出选择。


 动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree),红黑树 (Red-Black Tree ),B-tree/B+-tree/ B*-tree (B~Tree)。前三者是典型的二叉查找树结构,其查找的时间复杂度O(log2N)与树的深度相关,那么降低树的深度自然对查找效率是有所提高的;还有一个实际问题:就是大规模数据存储中,实现索引查询这样一个实际背景下,树节点存储的元素数量是有限的(如果元素数量非常多的话,查找就退化成节点内部的线性查找了),这样导致二叉查找树结构由于树的深度过大而造成磁盘I/O读写过于频繁,进而导致查询效率低下(为什么会出现这种情况,待会在外部存储器-磁盘中有所解释),那么如何减少树的深度(当然是不能减少查询的数据量),一个基本的想法就是:采用多叉树结构(由于树节点元素数量是有限的,自然该节点的子树数量也就是有限的)。

Indices》中首次提出。具体介绍可以参考wikipedia中的介绍:,其中还阐述了B-tree名字来源以及相关的开源地址。

计算机存储设备一般分为两种:内存储器(main memory)和外存储器(external memory)。内存存取速度快,但容量小,价格昂贵,而且不能长期保存数据(在不通电情况下数据会消失)。
外存储器—磁盘是一种直接存取的存储设备(DASD)。它是以存取时间变化不大为特征的。可以直接存取任何字符组,且容量大、速度较其它外存设备更快。

磁盘时一个扁平的圆盘(与电唱机的唱片类似)。盘面上有许多称为磁道的圆圈,数据就记录在这些磁道上。磁盘可以是单片的,也可以是由若干盘片组成的盘组,每一盘片上有两个面。如下图6片盘组为例,除去最顶端和最底端的外侧面不存储数据之外,一共有10个面可以用来保存信息。
当磁盘驱动器执行读/写功能时。盘片装在一个主轴上,并绕主轴高速旋转,当磁道在读/写头(又叫磁头) 下通过时,就可以进行数据的读 / 写了。
一般磁盘分为固定头盘(磁头固定)和活动头盘。固定头盘的每一个磁道上都有独立的磁头,它是固定不动的,专门负责这一磁道上数据的读/写。
活动头盘 (如上图)的磁头是可移动的。每一个盘面上只有一个磁头(磁头是双向的,因此正反盘面都能读写)。它可以从该面的一个磁道移动到另一个磁道。所有磁头都装在同一个动臂上,因此不同盘面上的所有磁头都是同时移动的(行动整齐划一)。当盘片绕主轴旋转的时候,磁头与旋转的盘片形成一个圆柱体。各个盘面上半径相同的磁道组成了一个圆柱面,我们称为柱面。因此,柱面的个数也就是盘面上的磁道数。

2.2磁盘的读/写原理和效率
磁盘上数据必须用一个三维地址唯一标示:柱面号、盘面号、块号(磁道上的盘块)。
读/写磁盘上某一指定数据需要下面3个步骤:
(1) 首先移动臂根据柱面号使磁头移动到所需要的柱面上,这一过程被称为定位或查找。
(2) 如上图6盘组示意图中,所有磁头都定位到了10个盘面的10条磁道上(磁头都是双向的)。这时根据盘面号来确定指定盘面上的磁道。
(3) 盘面确定以后,盘片开始旋转,将指定块号的磁道段移动至磁头下。
经过上面三个步骤,指定数据的存储位置就被找到。这时就可以开始读/写操作了。
访问某一具体信息,由3部分时间组成:
● 查找时间(seek time) Ts: 完成上述步骤(1)所需要的时间。这部分时间代价最高,最大可达到0.1s左右。
● 等待时间(latency time) Tl: 完成上述步骤(3)所需要的时间。由于盘片绕主轴旋转速度很快,一般为7200转/分(电脑硬盘的性能指标之一, 家用的普通硬盘的转速一般有5400rpm(笔记本)、7200rpm几种)。因此一般旋转一圈大约0.0083s。
磁盘读取数据是以盘块(block)为基本单位的。位于同一盘块中的所有数据都能被一次性全部读取出来。而磁盘IO代价主要花费在查找时间Ts上。因此我们应该尽量将相关信息存放在同一盘块,同一磁道中。或者至少放在同一柱面或相邻柱面上,以求在读/写信息时尽量减少磁头来回移动的次数,避免过多的查找时间Ts。
所以,在大规模数据存储方面,大量数据存储在外存磁盘中,而在外存磁盘中读取/写入块(block)中某数据时,首先需要定位到磁盘中的某块,如何有效地查找磁盘中的数据,需要一种合理高效的外存数据结构,就是下面所要重点阐述的B-tree结构,以及相关的变种结构:B+-tree结构和B*-tree结构。

B-tree又叫平衡多路查找树。一棵m阶的B-tree (m叉树)的特性如下:
(其中ceil(x)是一个取上限的函数)

1) 树中每个结点至多有m个孩子;
2) 除根结点和叶子结点外,其它每个结点至少有有ceil(m / 2)个孩子;
3) 若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点);
4) 所有叶子结点都出现在同一层,叶子结点不包含任何关键字信息(可以看做是外部结点或查询失败的结点,实际上这些结点不存在,指向这些结点的指针都为null);
5) 每个非终端结点中包含有n个关键字信息: (n,P0,K1,P1,K2,P2,……,Kn,Pn)。其中:
 b) Pi为指向子树根的接点,且指针P(i-1)指向子树种所有结点的关键字均小于Ki,但都大于K(i-1)。
B-tree中的每个结点根据实际情况可以包含大量的关键字信息和分支(当然是不能超过磁盘块的大小,根据磁盘驱动(disk drives)的不同,一般块的大小在1k~4k左右);这样树的深度降低了,这就意味着查找一个元素只要很少结点从外存磁盘中读入内存,很快访问到要查找的数据。


为了简单,这里用少量数据构造一棵3叉树的形式。上面的图中比如根结点,其中17表示一个磁盘文件的文件名;小红方块表示这个17文件的内容在硬盘中的存储位置;p1表示指向17左子树的指针。
其结构可以简单定义为:

/*指向子节点的指针*/ /*文件在硬盘中的存储位置*/

假如每个盘块可以正好存放一个B-tree的结点(正好存放2个文件名)。那么一个BTNode结点就代表一个盘块,而子树指针就是存放另外一个盘块的地址。
模拟查找文件29的过程:
(1) 根据根结点指针找到文件目录的根磁盘块1,将其中的信息导入内存。【磁盘IO操作1次】

(2) 此时内存中有两个文件名17,35和三个存储其他磁盘页面地址的数据。根据算法我们发现17<29<35,因此我们找到指针p2。

(3) 根据p2指针,我们定位到磁盘块3,并将其中的信息导入内存。【磁盘IO操作2次】

(4) 此时内存中有两个文件名26,30和三个存储其他磁盘页面地址的数据。根据算法我们发现26<29<30,因此我们找到指针p2。

(5) 根据p2指针,我们定位到磁盘块8,并将其中的信息导入内存。【磁盘IO操作3次】

(6) 此时内存中有两个文件名28,29。根据算法我们查找到文件29,并定位了该文件内存的磁盘地址。
分析上面的过程,发现需要3次磁盘IO操作和3次内存查找操作。关于内存中的文件名查找,由于是一个有序表结构,可以利用折半查找提高效率。至于3次磁盘IO操作时影响整个B-tree查找效率的决定因素。
当然,如果我们使用平衡二叉树的磁盘存储结构来进行查找,磁盘IO操作最少4次,最多5次。而且文件越多,B-tree比平衡二叉树所用的磁盘IO操作次数将越少,效率也越高。

上面仅仅介绍了对于B-tree这种结构的查找过程,还有树节点的插入与删除过程,以及相关的算法和代码的实现,将在以后的深入学习中给出相应的实例。

上面简单介绍了利用B-tree这种结构如何访问外存磁盘中的数据的情况,下面咱们通过另外一个实例来对这棵B-tree的插入(insert),删除(delete)基本操作进行详细的介绍:

下面以一棵5阶B-tree实例进行讲解(如下图所示):

其满足上述条件:除根结点和叶子结点外,其它每个结点至少有ceil(5/2)=3个孩子(至少2个关键字);当然最多5个孩子(最多4个关键字)。下图中关键字为大写字母,顺序为字母升序。

long Branch[5]; // 伪指针数组,(记录数目)方便判断合并和分裂的情况


插入(insert)操作:


 插入一个元素时,首先在B-tree中是否存在,如果不存在,即在叶子结点处结束,然后在叶子结点中插入该新的元素,注意:如果叶子结点空间足够,这里需要向右移动该叶子结点中大于新插入关键字的元素,如果空间满了以致没有足够的空间去添加新的元素,则将该结点进行“分裂”,将一半数量的关键字元素分裂到新的其相邻右结点中,中间关键字元素上移到父结点中(当然,如果父结点空间满了,也同样需要“分裂”操作),而且当结点中关键元素向右移动了,相关的指针也需要向右移。如果在根结点插入新元素,空间满了,则进行分裂操作,这样原来的根结点中的中间关键字元素向上移动到新的根结点中,因此导致树的高度增加一层。

咱们通过一个实例来逐步讲解下。插入以下字符字母到空的5阶B-tree中:C N G A H E K Q M F W L T Z D P R X Y S,5序意味着一个结点最多有5个孩子和4个关键字,除根结点外其他结点至少有2个关键字,首先,结点空间足够,4个字母插入相同的结点中,如下图:
当咱们试着插入H时,结点发现空间不够,以致将其分裂成2个结点,移动中间元素G上移到新的根结点中,在实现过程中,咱们把A和C留在当前结点中,而H和N放置新的其右邻居结点中。如下图:
当咱们插入E,K,Q时,不需要任何分裂操作
插入M需要一次分裂,注意M恰好是中间关键字元素,以致向上移到父节点中
插入F,W,L,T不需要任何分裂操作
插入Z时,最右的叶子结点空间满了,需要进行分裂操作,中间元素T上移到父节点中,注意通过上移中间元素,树最终还是保持平衡,分裂结果的结点存在2个关键字元素。
插入D时,导致最左边的叶子结点被分裂,D恰好也是中间元素,上移到父节点中,然后字母P,R,X,Y陆续插入不需要任何分裂操作。
最后,当插入S时,含有N,P,Q,R的结点需要分裂,把中间元素Q上移到父节点中,但是情况来了,父节点中空间已经满了,所以也要进行分裂,将父节点中的中间元素M上移到新形成的根结点中,注意以前在父节点中的第三个指针在修改后包括D和G节点中。这样具体插入操作的完成,下面介绍删除操作,删除操作相对于插入操作要考虑的情况多点。

首先查找B-tree中需删除的元素,如果该元素在B-tree中存在,则将该元素在其结点中进行删除,如果删除该元素后,首先判断该元素是否有左右孩子结点,如果有,则上移孩子结点中的某相近元素到父节点中,然后是移动之后的情况;如果没有,直接删除后,移动之后的情况.。

删除元素,移动相应元素之后,如果某结点中元素数目小于ceil(m/2)-1,则需要看其某相邻兄弟结点是否丰满(结点中元素个数大于ceil(m/2)-1),如果丰满,则向父节点借一个元素来满足条件;如果其相邻兄弟都刚脱贫,即借了之后其结点数目小于ceil(m/2)-1,则该结点与其相邻的某一兄弟结点进行“合并”成一个结点,以此来满足条件。那咱们通过下面实例来详细了解吧。
以上述插入操作构造的一棵5阶B-tree为例,依次删除H,T,R,E。
首先删除元素H,当然首先查找H,H在一个叶子结点中,且该叶子结点元素数目3大于最小元素数目ceil(m/2)-1=2,则操作很简单,咱们只需要移动K至原来H的位置,移动L至K的位置(也就是结点中删除元素后面的元素向前移动)
下一步,删除T,因为T没有在叶子结点中,而是在中间结点中找到,咱们发现他的继承者W(字母升序的下个元素),将W上移到T的位置,然后将原包含W的孩子结点中的W进行删除,这里恰好删除W后,该孩子结点中元素个数大于2,无需进行合并操作。
下一步删除R,R在叶子结点中,但是该结点中元素数目为2,删除导致只有1个元素,已经小于最小元素数目ceil(5/2)-1=2,如果其某个相邻兄弟结点中比较丰满(元素个数大于ceil(5/2)-1=2),则可以向父结点借一个元素,然后将最丰满的相邻兄弟结点中上移最后或最前一个元素到父节点中,在这个实例中,右相邻兄弟结点中比较丰满(3个元素大于2),所以先向父节点借一个元素W下移到该叶子结点中,代替原来S的位置,S前移;然后X在相邻右兄弟结点中上移到父结点中,最后在相邻右兄弟结点中删除X,后面元素前移。
最后一步删除E,删除后会导致很多问题,因为E所在的结点数目刚好达标,刚好满足最小元素个数(ceil(5/2)-1=2),而相邻的兄弟结点也是同样的情况,删除一个元素都不能满足条件,所以需要该节点与某相邻兄弟结点进行合并操作;首先移动父结点中的元素(该元素在两个需要合并的两个结点元素之间)下移到其子结点中,然后将这两个结点进行合并成一个结点。所以在该实例中,咱们首先将父节点中的元素D下移到已经删除E而只有F的结点中,然后将含有D和F的结点和含有A,C的相邻兄弟结点进行合并成一个结点。
也许你认为这样删除操作已经结束了,其实不然,在看看上图,对于这种特殊情况,你立即会发现父节点只包含一个元素G,没达标,这是不能够接受的。如果这个问题结点的相邻兄弟比较丰满,则可以向父结点借一个元素。假设这时右兄弟结点(含有Q,X)有一个以上的元素(Q右边还有元素),然后咱们将M下移到元素很少的子结点中,将Q上移到M的位置,这时,Q的左子树将变成M的右子树,也就是含有N,P结点被依附在M的右指针上。所以在这个实例中,咱们没有办法去借一个元素,只能与兄弟结点进行合并成一个结点,而根结点中的唯一元素M下移到子结点,这样,树的高度减少一层。
为了进一步详细讨论删除的情况。再举另外一个实例:
这里是一棵不同的5阶B-tree,那咱们试着删除C
于是将删除元素C的右子结点中的D元素上移到C的位置,但是出现上移元素后,只有一个元素的结点的情况。
又因为含有E的结点,其相邻兄弟结点才刚脱贫(最少元素个数为2),不可能向父节点借元素,所以只能进行合并操作,于是这里将含有A,B的左兄弟结点和含有E的结点进行合并成一个结点。
这样又出现只含有一个元素F结点的情况,这时,其相邻的兄弟结点是丰满的(元素个数为3>最小元素个数

2),这样就可以想父结点借元素了,把父结点中的J下移到该结点中,相应的如果结点中J后有元素则前移,然后相邻兄弟结点中的第一个元素(或者最后一个元素)上移到父节点中,后面的元素(或者前面的元素)前移(或者后移);注意含有K,L的结点以前依附在M的左边,现在变为依附在J的右边。这样每个结点都满足B-tree结构性质。
如果想了解相关代码,见最后参考。
B+-tree:是应文件系统所需而产生的一种B-tree的变形树。
1.有n棵子树的结点中含有n个关键字; (B-tree是n棵子树有n-1个关键字)

2.所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。 (B-tree的叶子节点并没有包括全部需要查找的信息)

3.所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (B-tree的非终节点也包含需要查找的有效信息)
a) 为什么说B+树比B-tree更适合实际应用中操作系统的文件索引和数据库索引?

B+-tree的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B-tree更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。

举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B-tree(一个结点最多8个关键字)的内部结点需要2个盘快。而B+-tree内部结点只需要1个盘快。当需要把内部结点读入内存中的时候,B-tree就比B+-tree多一次盘块查找时间(在磁盘中就是盘片旋转的时间)。

由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。


B-tree是B+-tree的变体,在B+-tree的非根和非叶子结点再增加指向兄弟的指针;B*-tree定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为2/3(代替B+树的1/2)。给出了一个简单实例,如下图所示:

当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+-tree的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针。
当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针。

所以,B*-tree分配新结点的概率比B+-tree要低,空间使用率更高;

B-tree:有序数组+平衡多叉树;

B+-tree:有序数组链表+平衡多叉树;

在大规模数据存储的文件系统中,B~tree系列数据结构,起着很重要的作用,对于存储不同的数据,节点相关的信息也是有所不同,这里根据自己的理解,画的一个查找以职工号为关键字,职工号为38的记录的简单示意图。(这里假设每个物理块容纳3个索引,磁盘的I/O操作的基本单位是块(block),磁盘访问很费时,采用B+-tree有效的减少了访问磁盘的次数。)
对于像MySQL,DB2,Oracle等数据库中的索引结构有待深入的了解才行,不过网上可以找到很多B-tree相关的开源代码可以用来研究。

在本视图中,每一个连接到数据库实例中的session都拥有一条记录。包括用户session及后台进程如DBWR,LGWR,arcchiver等等。

V$SESSION是基础信息视图,用于找寻用户SID或SADDR。不过,它也有一些列会动态的变化,可用于检查用户。如例:
注意:当使用SQL*Plus进行选择时,确认你重定义的列宽不小于11以便看到完整的数值。

数据库session被一个运行在数据库服务器上或从中间服务器甚至桌面通过SQL*Net连接到数据库的客户端进程启动,下列各列提供这个客户端的信息
l OSUSER: 客户端操作系统用户名
l PROGRAM:客户端执行的客户端程序

寻找被指定session执行的SQL语句是一个公共需求,如果session是瓶颈的主要原因,那根据其当前在执行的语句可以查看session在做些什么。

查询用户相关的各种统计信息.

b. 查询用户相关的各种io统计信息

c. 查询用户想在正在打开着的游标变量.

d. 查询用户当前的等待信息. 以查看当前的语句为什么这么慢/在等待什么资源.

e. 查询用户在一段时间内所等待的各种事件的信息. 以了解这个session所遇到的瓶颈

2. paddr.字段, process addr, 通过这个字段我们可以查看当前进程的相关信息, 系统进程id,操作系统用户信息等等.

taddr 当前事务的地址,可以通过这个字段查看当前session正在执行的事务信息, 使用的回滚段信息等

lockwait字段, 可以通过这个字段查询出当前正在等待的锁的相关信息.

c. 在根据以上四个字段构造出被锁的字段的rowid信息.


在使用DBMS_STATS分析表的时候,我们经常要保存之前的分析,以防分析后导致系统性能低下然后进行快速恢复。

1、首先创建一个分析表,该表是用来保存之前的分析值:
PL/SQL 过程已成功完成。
PL/SQL 过程已成功完成。
PL/SQL 过程已成功完成。 PL/SQL 过程已成功完成。
PL/SQL 过程已成功完成。

我要回帖

更多关于 okrrrr发音 的文章

 

随机推荐