精华内容
下载资源
问答
  • 核心对象概念 基本对象 1. Pod Pod是最小部署单元,一个Pod有一个或多个容器组成,Pod中容器共享存储和网络,在同一台Docker主机上运行。 2. Service Service一个应用服务抽象,定义了Pod逻辑集合和访问这个Pod...

    Kubernetes介绍

    Kubernetes是Google在2014年开源的一个容器集群管理系统,使用Go语言开发,Kuberneter也叫K8S
    K8S是Google内部一个叫Borg的容器集群管理系统衍生出来的,Borg已经在Google大规模生产运行十年之久。
    K8S主要用于自动化部署、扩展和管理容器应用。提供了资源调度、部署管理、服务发现、扩容缩容、监控等一整套功能。
    Kuberneter目标是让部署容器化应用简单高效

    Kubernetes主要功能:

    image

    1. 数据卷
    Pod中容器之间共享数据,可以使用数据卷。
    2. 应用程序健康检查
    容器内服务可能进程堵塞无法处理请求,可以设置监控检查策略保证应用健壮性。
    3. 复制应用程序实例
    控制器维护着Pod副本数量,保证一个Pod或一组同类的Pod数量始终可用。
    4. 弹性伸缩
    根据设定的指标(CPU利用率)自动缩放Pod副本数
    5. 服务发现
    使用环境变量或DNS服务插件保证容器中程序发现Pod入口访问地址。
    6. 负载均衡
    一组Pod副本分配一个私有的集群IP地址,负载均衡转发请求到后继容器。在集群内部其他Pod可通过这个ClusterIP访问应用。
    7. 滚动更新
    更新服务不中断,一次更新一个Pod,而不是同时删除整个服务。
    8. 服务编排
    通过文件描述部署服务,使的应用程序部署变得更高效。
    9. 资源监控
    Node节点组件集成cAdvisor资源收集工具,可通过Heapster汇总整个集群节点资源数据,然后存储到InfluxDB时序数据库,再由Grafana展示。
    10. 提供认证和授权
    支持角色访问控制(RBAC)认证授权等策略。

    核心对象概念

    基本对象
    1. Pod
    Pod是最小部署单元,一个Pod有一个或多个容器组成,Pod中容器共享存储和网络,在同一台Docker主机上运行。
    2. Service
    Service一个应用服务抽象,定义了Pod逻辑集合和访问这个Pod集合的策略。
    Service代理Pod集合对外表现是为一个访问入口,分配一个集群IP地址,来自这个IP的请求将负载均衡转发后端Pod中的容器。
    Service通过Lable Selector选择一组Pod提供服务。
    3. Volume
    数据卷,共享Pod中容器使用的数据。
    4. Namespace
    命名空间将对象逻辑上分配到不同Namespace,可以是不同的项目、用户等区分管理,并设定控制策略,从而实现多租户。
    命名空间也称为虚拟集群。
    5. Lable
    标签用于区分对象(比如Pod、Service),键/值对存在;每个对象可以有多个标签,通过标签关联对象。
    ### 基于基本对象更高层次抽象:
    1. ReplicaSet
    下一代Replication Controller。确保任何给定时间指定的Pod副本数量,并提供声明式更新等功能。
    RC与RS唯一区别就是lable selector支持不同,RS支持新的基于集合的标签。RS支持新的基于集合的标签,RC仅支持基于等式的标签。
    2. Deployment
    Deployment是一个更高层次的API对象,它管理ReplicaSets和Pod,并提供声明式更新等功能。
    官方建议使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,这就意味着可能永远不需要直接操作ReplicaSet对象。
    3. StatefulSet
    StatefulSet适合持久性的应用程序,有唯一的网络标识符(IP),持久储存,有序的部署、扩展、删除和滚动更新。
    4. DaemonSet
    DaemonSet确保所有(或一些)节点运行同一个Pod、当节点加入Kubernetes集群中,Pod会被调度到节点上运行,当节点从集群中移除时,DaemonSet的Pod会被删除,删除DaemonSet会清理它所有创建的Pod。
    5. Job
    一次性任务,运行完成后Pod销毁,不再重新启动新容器。还可以任务定时运行。

    展开全文
  • 面向对象基础概念

    千次阅读 2007-05-30 17:27:00
    面向对象概念和应用已超越了程序设计和软件开发,扩展到很宽的范围。如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。 谈到面向对象,这方面的文章非常多。...

          OO(Object Oriented,面向对象)是当前计算机界关心的重点,它是90年代软件开发方法的主流。面向对象的概念和应用已超越了程序设计软件开发,扩展到很宽的范围。如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。

     

          谈到面向对象,这方面的文章非常多。但是,明确地给出对象的定义或说明对象的定义的非常少——至少我现在还没有发现。其初,“面向对象”是专指在程序设计中采用封装、继承、抽象等设计方法。可是,这个定义显然不能再适合现在情况。面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(OOAObject Oriented Analysis),面向对象的设计(OOD,Object Oriented Design)、以及我们经常说的面向对象的编程实现(OOPObject Oriented Programming)。许多有关面向对象的文章都只是讲述在面向对象的开发中所需要注意的问题或所采用的比较好的设计方法。看这些文章只有真正懂得什么是对象,什么是面向对象,才能最大程度地对自己有所裨益。这一点,恐怕对初学者甚至是从事相关工作多年的人员也会对它们的概念模糊不清。

     

          面向对象是当前计算机界关心的重点,它是90年代软件开发方法的主流。面向对象的概念和应用已超越了程序设计和软件开发,扩展到很宽的范围。如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。 

    一、传统开发方法存在问题

          1.软件重用性差
          重用性是指同一事物不经修改或稍加修改就可多次重复使用的性质。软件重用性是软件工程追求的目标之一。

          2.软件可维护性差
          软件工程强调软件的可维护性,强调文档资料的重要性,规定最终的软件产品应该由完整、一致的配置成分组成。在软件开发过程中,始终强调软件的可读性、可修改性和可测试性是软件的重要的质量指标。实践证明,用传统方法开发出来的软件,维护时其费用和成本仍然很高,其原因是可修改性差,维护困难,导致可维护性差。

          3.开发出的软件不能满足用户需要
          用传统的结构化方法开发大型软件系统涉及各种不同领域的知识,在开发需求模糊或需求动态变化的系统时,所开发出的软件系统往往不能真正满足用户的需要。

          用结构化方法开发的软件,其稳定性、可修改性和可重用性都比较差,这是因为结构化方法的本质是功能分解,从代表目标系统整体功能的单个处理着手,自顶向下不断把复杂的处理分解为子处理,这样一层一层的分解下去,直到仅剩下若干个容易实现的子处理功能为止,然后用相应的工具来描述各个最低层的处理。因此,结构化方法是围绕实现处理功能的“过程”来构造系统的。然而,用户需求的变化大部分是针对功能的,因此,这种变化对于基于过程的设计来说是灾难性的。用这种方法设计出来的系统结构常常是不稳定的 ,用户需求的变化往往造成系统结构的较大变化,从而需要花费很大代价才能实现这种变化。

    二、面向对象的基本概念

          (1)对象。
          对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。

          (2)对象的状态和行为。
          对象具有状态,一个对象用数据值来描述它的状态。
          对象还有操作,用于改变对象的状态,对象及其操作就是对象的行为。
          对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中

          (3)
          具有相同或相似性质的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象。
          类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。
          类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。

          (4)类的结构。
          在客观世界中有若干类,这些类之间有一定的结构关系。通常有两种主要的结构关系,即一般--具体结构关系,整体--部分结构关系。

          ①一般——具体结构称为分类结构,也可以说是“或”关系,或者是“is a”关系。
          ②整体——部分结构称为组装结构,它们之间的关系是一种“与”关系,或者是“has a”关系。

          (5)消息和方法。
          对象之间进行通信的结构叫做消息。在对象的操作中,当一个消息发送给某个对象时,消息包含接收对象去执行某种操作的信息。发送一条消息至少要包括说明接受消息的对象名、发送给该对象的消息名(即对象名、方法名)。一般还要对参数加以说明,参数可以是认识该消息的对象所知道的变量名,或者是所有对象都知道的全局变量名。

          类中操作的实现过程叫做方法,一个方法有方法名、参数、方法体。消息传递如图10-1所示。


    二、面向对象的特征

          (1)对象唯一性。
          每个对象都有自身唯一的标识,通过这种标识,可找到相应的对象。在对象的整个生命期中,它的标识都不改变,不同的对象不能有相同的标识。

          (2)分类性。
          分类性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是这样一种抽象,它反映了与应用有关的重要性质,而忽略其他一些无关内容。任何类的划分都是主观的,但必须与具体的应用有关。

          (3)继承性。
          继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。

          继承性是面向对象程序设计语言不同于其它语言的最重要的特点,是其他语言所没有的。

          在类层次中,子类只继承一个父类的数据结构和方法,则称为单重继承。
          在类层次中,子类继承了多个父类的数据结构和方法,则称为多重继承。
          在软件开发中,类的继承性使所建立的软件具有开放性、可扩充性,这是信息组织与分类的行之有效的方法,它简化了对象、类的创建工作量,增加了代码的可重性。
          采用继承性,提供了类的规范的等级结构。通过类的继承关系,使公共的特性能够共享,提高了软件的重用性。

          (4)多态性(多形性)
          多态性使指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。
          多态性允许每个对象以适合自身的方式去响应共同的消息。
          多态性增强了软件的灵活性和重用性。

    三、面向对象的要素

          (1)抽象。
          抽象是指强调实体的本质、内在的属性。在系统开发中,抽象指的是在决定如何实现对象之前的对象的意义和行为。使用抽象可以尽可能避免过早考虑一些细节。

          类实现了对象的数据(即状态)和行为的抽象。
     
          (2)封装性(信息隐藏)。
          封装性是保证软件部件具有优良的模块性的基础。
          面向对象的类是封装良好的模块,类定义将其说明(用户可见的外部接口)与实现(用户不可见的内部实现)显式地分开,其内部实现按其具体定义的作用域提供保护。
          对象是封装的最基本单位。封装防止了程序相互依赖性而带来的变动影响。面向对象的封装比传统语言的封装更为清晰、更为有力。

          (3)共享性
          面向对象技术在不同级别上促进了共享
          同一类中的共享。同一类中的对象有着相同数据结构。这些对象之间是结构、行为特征的共享关系。
          在同一应用中共享。在同一应用的类层次结构中,存在继承关系的各相似子类中,存在数据结构和行为的继承,使各相似子类共享共同的结构和行为。使用继承来实现代码的共享,这也是面向对象的主要优点之一。
          在不同应用中共享。面向对象不仅允许在同一应用中共享信息,而且为未来目标的可重用设计准备了条件。通过类库这种机制和结构来实现不同应用中的信息共享。

          4.强调对象结构而不是程序结构

    四、面向对象的开发方法

          目前,面向对象开发方法的研究已日趋成熟,国际上已有不少面向对象产品出现。面向对象开发方法有Coad方法、Booch方法和OMT方法等。

          1.Booch方法

          Booch最先描述了面向对象的软件开发方法的基础问题,指出面向对象开发是一种根本不同于传统的功能分解的设计方法。面向对象的软件分解更接近人对客观事务的理解,而功能分解只通过问题空间的转换来获得。

          2.Coad方法

          Coad方法是1989年Coad和Yourdon提出的面向对象开发方法。该方法的主要优点是通过多年来大系统开发的经验与面向对象概念的有机结合,在对象、结构、属性和操作的认定方面,提出了一套系统的原则。该方法完成了从需求角度进一步进行类和类层次结构的认定。尽管Coad方法没有引入类和类层次结构的术语,但事实上已经在分类结构、属性、操作、消息关联等概念中体现了类和类层次结构的特征。

          3.OMT方法

          OMT方法是1991年由James Rumbaugh等5人提出来的,其经典著作为“面向对象的建模与设计”。

          该方法是一种新兴的面向对象的开发方法,开发工作的基础是对真实世界的对象建模,然后围绕这些对象使用分析模型来进行独立于语言的设计,面向对象的建模和设计促进了对需求的理解,有利于开发得更清晰、更容易维护的软件系统。该方法为大多数应用领域的软件开发提供了一种实际的、高效的保证,努力寻求一种问题求解的实际方法。

          4.UML(Unified Modeling Language)语言

          软件工程领域在1995年~1997年取得了前所未有的进展,其成果超过软件工程领域过去15年的成就总和,其中最重要的成果之一就是统一建模语言(UML)的出现。UML将是面向对象技术领域内占主导地位的标准建模语言
    UML不仅统一了Booch方法、OMT方法、OOSE方法的表示方法,而且对其作了进一步的发展,最终统一为大众接受的标准建模语言。UML是一种定义良好、易于表达、功能强大且普遍适用的建模语言。它融入了软件工程领域的新思想、新方法和新技术。它的作用域不限于支持面向对象的分析与设计,还支持从需求分析开始的软件开发全过程。

    五、面向对象的模型

     ·对象模型

          对象模型表示了静态的、结构化的系统数据性质,描述了系统的静态结构,它是从客观世界实体的对象关系角度来描述,表现了对象的相互关系。该模型主要关心系统中对象的结构、属性和操作,它是分析阶段三个模型的核心,是其他两个模型的框架

          1.对象和类

          (1) 对象。
          对象建模的目的就是描述对象。

          (2) 类。
          通过将对象抽象成类,我们可以使问题抽象化,抽象增强了模型的归纳能力。

          (3) 属性。
          属性指的是类中对象所具有的性质(数据值)。

          (4) 操作和方法。

          操作是类中对象所使用的一种功能或变换。类中的各对象可以共享操作,每个操作都有一个目标对象作为其隐含参数。
      方法是类的操作的实现步骤。

          2.关联和链
          关联是建立类之间关系的一种手段,而链则是建立对象之间关系的一种手段。

          (1) 关联和链的含义。
          链表示对象间的物理与概念联结,关联表示类之间的一种关系,链是关联的实例,关联是链的抽象。

          (2) 角色。
          角色说明类在关联中的作用,它位于关联的端点。

          (3) 受限关联。
          受限关联由两个类及一个限定词组成,限定词是一种特定的属性,用来有效的减少关联的重数,限定词在关联的终端对象集中说明。
          限定提高了语义的精确性,增强了查询能力,在现实世界中,常常出现限定词。

          (4) 关联的多重性。
          关联的多重性是指类中有多少个对象与关联的类的一个对象相关。重数常描述为“一”或“多”。
          图10-8表示了各种关联的重数。小实心圆表示“多个”,从零到多。小空心圆表示零或一。没有符号表示的是一对一关联。

          3.类的层次结构
          (1) 聚集关系。
          聚集是一种“整体-部分”关系。在这种关系中,有整体类和部分类之分。聚集最重要的性质是传递性,也具有逆对称性。


          聚集可以有不同层次,可以把不同分类聚集起来得到一颗简单的聚集树,聚集树是一种简单表示,比画很多线来将部分类联系起来简单得多,对象模型应该容易地反映各级层次,图10-10表示一个关于微机的多极聚集。

           (2)一般化关系。
          一般化关系是在保留对象差异的同时共享对象相似性的一种高度抽象方式。它是“一般---具体”的关系。一般化类称为你类,具体类又能称为子类,各子类继承了交类的性质,而各子类的一些共同性质和操作又归纳到你类中。因此,一般化关系和继承是同时存在的。一般化关系的符号表示是在类关联的连线上加一个小三角形,如图10-11

          4.对象模型
          (1)模板。模板是类、关联、一般化结构的逻辑组成。
          (2)对象模型。

          对象模型是由一个或若干个模板组成。模板将模型分为若干个便于管理的子块,在整个对象模型和类及关联的构造块之间,模板提供了一种集成的中间单元,模板中的类名及关联名是唯一的。

    ·动态模型

          动态模型是与时间和变化有关的系统性质。该模型描述了系统的控制结构,它表示了瞬间的、行为化的系统控制
    性质,它关心的是系统的控制,操作的执行顺序,它表示从对象的事件和状态的角度出发,表现了对象的相互行为。
    该模型描述的系统属性是触发事件、事件序列、状态、事件与状态的组织。使用状态图作为描述工具。它涉及到事件、状态、操作等重要概念。
           1.事件
          事件是指定时刻发生的某件事。

           2.状态
           状态是对象属性值的抽象。对象的属性值按照影响对象显著行为的性质将其归并到一个状态中去。状态指明了对象
    对输入事件的响应。

          3.状态图

          状态图是一个标准的计算机概念,他是有限自动机的图形表示,这里把状态图作为建立动态模型的图形工具。
          状态图反映了状态与事件的关系。当接收一事件时,下一状态就取决于当前状态和所接收的该事件,由该事件引起的状态变化称为转换。
          状态图是一种图,用结点表示状态,结点用圆圈表示;圆圈内有状态名,用箭头连线表示状态的转换,上面标记事件名,箭头方向表示转换的方向。

    ·功能模型

          功能模型描述了系统的所有计算。功能模型指出发生了什么,动态模型确定什么时候发生,而对象模型确定发生的客体。功能模型表明一个计算如何从输入值得到输出值,它不考虑计算的次序。功能模型由多张数据流图组成。数据流图用来表示从源对象到目标对象的数据值的流向,它不包含控制信息,控制信息在动态模型中表示,同时数据流图也不表示对象中值的组织,值的组织在对象模型中表示。图10-15给出了一个窗口系统的图标显示的数据流图。

           数据流图中包含有处理、数据流、动作对象和数据存储对象。

          1.处理
           数据流图中的处理用来改变数据值。最低层处理是纯粹的函数,一张完整的数据流图是一个高层处理。

           2.数据流
           数据流图中的数据流将对象的输出与处理、处理与对象的输入、处理与处理联系起来。在一个计算机中,用数据流来表示一中间数据值,数据流不能改变数据值。

          3.动作对象
           动作对象是一种主动对象,它通过生成或者使用数据值来驱动数据流图。

          4.数据存储对象
          数据流图中的数据存储是被动对象,它用来存储数据。它与动作对象不一样,数据存储本身不产生任何操作,它只响应存储和访问的要求。


    六、面向对象的分析

          面向对象分析的目的是对客观世界的系统进行建模。本节以上面介绍的模型概念为基础,结合“银行网络系统”的具体实例来构造客观世界问题的准确、严密的分析模型。
          分析模型有三种用途:用来明确问题需求;为用户和开发人员提供明确需求;为用户和开发人员提供一个协商的基础,作为后继的设计和实现的框架。

    (一) 面向对象的分析

         系统分析的第一步是:陈述需求。分析者必须同用户一块工作来提炼需求,因为这样才表示了用户的真实意图,其中涉及对需求的分析及查找丢失的信息。下面以“银行网络系统”为例,用面向对象方法进行开发。
    银行网络系统问题陈述: 设计支持银行网络的软件,银行网络包括人工出纳站和分行共享的自动出纳机。每个分理处用分理处计算机来保存各自的帐户,处理各自的事务;各自分理处的出纳站与分理处计算机通信,出纳站录入帐户和事务数据;自动出纳机与分行计算机通信,分行计算机与拨款分理处结帐,自动出纳机与用户接口接受现金卡,与分行计算机通信完成事务,发放现金,打印收据;系统需要记录保管和安全措施;系统必须正确处理同一帐户的并发访问;每个分处理为自己的计算机准备软件,银行网络费用根据顾客和现金卡的数目分摊给各分理处。
    图10-18给出银行网络系统的示意图。


    (二)建立对象模型

          首先标识和关联,因为它们影响了整体结构和解决问题的方法,其次是增加属性,进一步描述类和关联的基本网络,使用继承合并和组织类,最后操作增加到类中去作为构造动态模型和功能模型的副产品。

          1.确定类

          构造对象模型的第一步是标出来自问题域的相关的对象类,对象包括物理实体和概念。所有类在应用中都必须有意义,在问题陈述中,并非所有类都是明显给出的。有些是隐含在问题域或一般知识中的。

    按图10-19所示的过程确定类
       

    查找问题陈述中的所有名词,产生如下的暂定类。
     软件            银行网络         出纳员        自动出纳机           分行
     分处理          分处理计算机     帐户          事务                 出纳站
     事务数据        分行计算机       现金卡        用户                 现金
     收据            系统             顾客          费用                 帐户数据
     访问            安全措施         记录保管

         根据下列标准,去掉不必要的类和不正确的类。
     (1) 冗余类:若两个类表述了同一个信息 ,保留最富有描述能力的类。如"用户"和"顾客"就是重复的描述,因为"顾客"最富有描述性,因此保留它。
     (2) 不相干的类:除掉与问题没有关系或根本无关的类。例如,摊派费用超出了银行网络的范围。
     (3) 模糊类:类必须是确定的,有些暂定类边界定义模糊或范围太广,如"记录保管"就模糊类,它是"事务"中的一部分。
     (4) 属性:某些名词描述的是其他对象的属性,则从暂定类中删除。如果某一性质的独立性很重要,就应该把他归属到类,而不把它作为属性。
     (5) 操作:如果问题陈述中的名词有动作含义,则描述的操作就不是类。但是具有自身性质而且需要独立存在的操作应该描述成类。如我们只构造电话模型,"拨号"就是动态模型的一部分而不是类,但在电话拨号系统中,"拨号"是一个重要的类,它日期、时间、受话地点等属性。

          在银行网络系统中,模糊类是"系统"、"安全措施"、"记录保管"、"银行网络"等。属于属性的有:"帐户数据"、"收据"、"现金"、"事务数据"。属于实现的如:"访问"、"软件"等。这些均应除去。

       2.准备数据字典

       为所有建模实体准备一个数据字典。准确描述各个类的精确含义,描述当前问题中的类的范围,包括对类的成员、用法方面的假设或限制。

       3.确定关联

       两个或多个类之间的相互依赖就是关联。一种依赖表示一种关联,可用各种方式来实现关联,但在分析模型中应删除实现的考虑,以便设计时更为灵活。关联常用描述性动词或动词词组来表示,其中有物理位置的表示、传导的动作、通信、所有者关系、条件的满足等。从问题陈述中抽取所有可能的关联表述,把它们记下来,但不要过早去细化这些表述。

      下面是银行网络系统中所有可能的关联,大多数是直接抽取问题中的动词词组而得到的。在陈述中,有些动词词组表述的关联是不明显的。最后,还有一些关联与客观世界或人的假设有关,必须同用户一起核实这种关联,因为这种关联在问题陈述中找不到。

       银行网络问题陈述中的关联:
     ·银行网络包括出纳站和自动出纳机;
     ·分行共享自动出纳机;
     ·分理处提供分理处计算机;
     ·分理处计算机保存帐户;
     ·分理处计算机处理帐户支付事务;
     ·分理处拥有出纳站;
     ·出纳站与分理处计算机通信;
     ·出纳员为帐户录入事务;
     ·自动出纳机接受现金卡;
     ·自动出纳机与用户接口;
     ·自动出纳机发放现金;
     ·自动出纳机打印收据;
     ·系统处理并发访问;
     ·分理处提供软件;
     ·费用分摊给分理处。
      隐含的动词词组:
     ·分行由分理处组成;
     ·分理处拥有帐户;
     ·分行拥有分行计算机;
     ·系统提供记录保管;
     ·系统提供安全;
     ·顾客有现金卡。
      基于问题域知识的关联:
     ·分理处雇佣出纳员;
     ·现金卡访问帐户。

      使用下列标准去掉不必要和不正确的关联:

     (1) 若某个类已被删除,那么与它有关的关联也必须删除或者用其它类来重新表述。在例中,我们删除了"银行网络",相关的关联也要删除。
     (2) 不相干的关联或实现阶段的关联:删除所有问题域之外的关联或涉及实现结构中的关联。如"系统处理并发访问"就是一种实现的概念。
     (3) 动作:关联应该描述应用域的结构性质而不是瞬时事件,因此应删除"自动出纳机接受现金卡","自动出纳机与用户接口"等。
     (4) 派生关联:省略那些可以用其他关联来定义的关联。因为这种关联是冗余的。银行网络系统的初步对象图如图10-20所示。其中含有关联。

         4.确定属性

       属性是个体对象的性质,属性通常用修饰性的名词词组来表示.形容词常常表示具体的可枚举的属性值,属性不可能在问题陈述中完全表述出来,必须借助于应用域的知识及对客观世界的知识才可以找到它们。只考虑与具体应用直接相关的属性,不要考虑那些超出问题范围的属性。首先找出重要属性,避免那些只用于实现的属性,要为各个属性取有意义的名字。按下列标准删除不必要的和不正确的属性:

     (1) 对象:若实体的独立存在比它的值重要,那么这个实体不是属性而是对象。如在邮政目录中,"城市"是一个属性,然而在人口普查中,"城市"则被看作是对象。在具体应用中,具有自身性质的实体一定是对象。
     (2) 定词:若属性值取决于某种具体上下文,则可考虑把该属性重新表述为一个限定词。
     (3) 名称:名称常常作为限定词而不是对象的属性,当名称不依赖于上下文关系时,名称即为一个对象属性,尤其是它不惟一时。
     (4) 标识符:在考虑对象模糊性时,引入对象标识符表示,在对象模型中不列出这些对象标识符,它是隐含在对象模型中,只列出存在于应用域的属性。
     (5) 内部值:若属性描述了对外不透明的对象的内部状态,则应从对象模型中删除该属性。
     (6) 细化:忽略那些不可能对大多数操作有影响的属性。

      5.使用继承来细化类

       使用继承来共享公共机构,以次来组织类,可以用两种方式来进行。
     (1) 自底向上通过把现有类的共同性质一般化为父类,寻找具有相似的属性,关系或操作的类来发现继承。例如"远程事务"和"出纳事务"是类似的,可以一般化为"事务"。有些一般化结构常常是基于客观世界边界的现有分类,只要可能,尽量使用现有概念。对称性常有助于发现某些丢失的类。
     (2) 自顶向下将现有的类细化为更具体的子类。具体化常常可以从应用域中明显看出来。应用域中各枚举字情况是最常见的具体化的来源。例如:菜单,可以有固定菜单,顶部菜单,弹出菜单,下拉菜单等,这就可以把菜单类具体细化为各种具体菜单的子类。当同一关联名出现多次且意义也相同时,应尽量具体化为相关联的类,例如"事务"从"出纳站"和"自动出纳机"进入,则"录入站"就是"出纳站"和"自动出纳站"的一般化。在类层次中,可以为具体的类分配属性和关联。各属性和都应分配给最一般的适合的类,有时也加上一些修正。

          应用域中各枚举情况是最常见的具体化的来源。

       6.完善对象模型

       对象建模不可能一次就能保证模型是完全正确的,软件开发的整个过程就是一个不断完善的过程。模型的不同组成部分多半是在不同的阶段完成的,如果发现模型的缺陷,就必须返回到前期阶段去修改,有些细化工作是在动态模型和功能模型完成之后才开始进行的。
      (1) 几种可能丢失对象的情况及解决办法:
     ·同一类中存在毫无关系的属性和操作,则分解这个类,使各部分相互关联;
     ·一般化体系不清楚,则可能分离扮演两种角色的类
     ·存在无目标类的操作,则找出并加上失去目标的类;
     ·存在名称及目的相同的冗余关联,则通过一般化创建丢失的父类,把关联组织在一起。

      (2) 查找多余的类。
      类中缺少属性,操作和关联,则可删除这个类。

      (3)查找丢失的关联。
       丢失了操作的访问路径,则加入新的关联以回答查询。

      (4) 网络系统的具体情况作如下的修改:
     ①现金卡有多个独立的特性。把它分解为两个对象:卡片权限和现金卡。
     a.卡片权限:它是银行用来鉴别用户访问权限的卡片,表示一个或多个用户帐户的访问权限;各个卡片权限对象中可能具有好几个现金卡,每张都带有安全码,卡片码,它们附在现金卡上,表现银行的卡片权限。
     b.现金卡:它是自动出纳机得到表示码的数据卡片,它也是银行代码和现金卡代码的数据载体。
     ②"事务"不能体现对帐户之间的传输描述的一般性,因它只涉及一个帐户,一般来说,在每个帐户中,一个"事务"包括一个或多个"更新",一个"更新"是对帐户的一个动作,它们是取款,存款,查询之一。一个"更新"中所有"更新"应该是一个原子操作。
     ③"分理处"和"分离处理机"之间,"分行"和"分行处理机"之间的区别似乎并不影响分析,计算机的通信处理实际上是实现的概念,将"分理处计算机"并入到"分理处",将"分行计算机"并入到"分行"。

    (三)建立动态模型

       1.准备脚本
       动态分析从寻找事件开始,然后确定各对象的可能事件顺序。在分析阶段不考虑算法的执行,算法是实现模型的一部分。

       2.确定事件
       确定所有外部事件。事件包括所有来自或发往用户的信息、外部设备的信号、输入、转换和动作,可以发现正常事件,但不能遗漏条件和异常事件。

       3.准备事件跟踪表
       把脚本表示成一个事件跟踪表,即不同对象之间的事件排序表,对象为表中的列,给每个对象分配一个独立的列。


       4.构造状态图
       对各对象类建立状态图,反映对象接收和发送的事件,每个事件跟踪都对应于状态图中一条路径。

    (四)建立功能建模

       功能模型用来说明值是如何计算的,表明值之间的依赖关系及相关的功能,数据流图有助于表示功能依赖关系,其中的处理应于状态图的活动和动作,其中的数据流对应于对象图中的对象或属性。

       1.确定输入值、输出值
       先列出输入、输出值,输入、输出值是系统与外界之间的事件的参数。

       2.建立数据流图
       数据流图说明输出值是怎样从输入值得来的,数据流图通常按层次组织。

    (五)确定操作

       在建立对象模型时,确定了类、关联、结构和属性,还没有确定操作。只有建立了动态模型和功能模型之后,才可能最后确定类的操作。

    七、面向对象的设计

       面向对象设计是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。从面向对象分析到面向对象设计,是一个逐渐扩充模型的过程。

       瀑布模型把设计进一步划分成概要设计和详细设计两个阶段,类似地,也可以把面向对象设计再细分为系统设计和对象设计。系统设计确定实现系统的策略和目标系统的高层结构。对象设计确定解空间中的类、关联、接口形式及实现操作的算法。

    (一)面向对象设计的准则

       1.模块化
       面向对象开发方法很自然地支持了把系统分解成模块的设计原则:对象就是模块。它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。
       2.抽象
       面向对象方法不仅支持过程抽象,而且支持数据抽象。
       3.信息隐藏
       在面向对象方法中,信息隐藏通过对象的封装性来实现。
       4.低耦合
       在面向对象方法中,对象是最基本的模块,因此,耦合主要指不同对象之间相互关联的紧密程度。低耦合是设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其它部分的影响降到最低程度。
       5.高内聚
       (1)操作内聚。
       (2)类内聚。
       (3)一般——具体内聚。

    (二)面向对象设计的启发规则

       1.设计结果应该清晰易懂
       使设计结果清晰、易懂、易读是提高软件可维护性和可重用性的重要措施。显然,人们不会重用那些他们不理解的设计。
       要做到:
       (1)用词一致。
       (2)使用已有的协议。
       (3)减少消息模式的数量。
       (4)避免模糊的定义。

       2.一般——具体结构的深度应适当

       3.设计简单类
       应该尽量设计小而简单的类,这样便以开发和管理。为了保持简单,应注意以下几点:
       (1)避免包含过多的属性。
       (2)有明确的定义。
       (3)尽量简化对象之间的合作关系。
       (4)不要提供太多的操作。

       4.使用简单的协议
       一般来说,消息中参数不要超过3个。

       5.使用简单的操作
       面向对象设计出来的类中的操作通常都很小,一般只有3至5行源程序语句,可以用仅含一个动词和一个宾语的简单句子描述它的功能

       6.把设计变动减至最小
       通常,设计的质量越高,设计结果保持不变的时间也越长。即使出现必须修改设计的情况,也应该使修改的范围尽可能小。
    (三)系统设计

       系统设计是问题求解及建立解答的高级策略。必须制定解决问题的基本方法,系统的高层结构形式包括子系统的分解、它的固有并发性、子系统分配给硬软件、数据存储管理、资源协调、软件控制实现、人机交互接口。

    1.系统设计概述

        设计阶段先从高层入手,然后细化。系统设计要决定整个结构及风格,这种结构为后面设计阶段的更详细策略的设计提供了基础。

       (1)系统分解。
       系统中主要的组成部分称为子系统,子系统既不是一个对象也不是一个功能,而是类、关联、操作、事件和约束的集合。
       (2)确定并发性。
       分析模型、现实世界及硬件中不少对象均是并发的。
       (3)处理器及任务分配。
       各并发子系统必须分配给单个硬件单元,要么是一个一般的处理器,要么是一个具体的功能单元。
       (4)数据存储管理。
       系统中的内部数据和外部数据的存储管理是一项重要的任务。通常各数据存储可以将数据结构、文件、数据库组合在一起,不同数据存储要在费用、访问时间、容量及可靠性之间做出折衷考虑。
       (5)全局资源的处理。
       必须确定全局资源,并且制定访问全局资源的策略。
       (6)选择软件控制机制。
       分析模型中所有交互行为都表示为对象之间的事件。系统设计必须从多种方法中选择某种方法来实现软件的控制。
       (7)人机交互接口设计。
       设计中的大部分工作都与稳定的状态行为有关,但必须考虑用户使用系统的交互接口。

       2.系统结构的一般框架

       3.系统分解——建立系统的体系结构
       可用的软件库以及程序员的编程经验。
       通过面向对象分析得到的问题域精确模型,为设计体系结构奠定了良好的基础,建立了完整的框架。

       4.选择软件控制机制
       软件系统中存在两种控制流,外部控制流和内部控制流。

       5.数据存储管理
       数据存储管理是系统存储或检索对象的基本设施,它建立在某种数据存储管理系统之上,并且隔离了数据存储管理模式的影响。

       6.设计人机交互接口
       在面向对象分析过程中,已经对用户界面需求作了初步分析,在面向对象设计过程中,则应该对系统的人机交互接口进行详细设计,以确定人机交互的细节,其中包括指定窗口和报表的形式、设计命令层次等项内容。

    (四)对象设计
       1.对象设计概述
       2.三种模型的结合
       (1)获得操作。
       (2)确定操作的目标对象。
       3.算法设计
       4.优化设计
       5.控制的实现
       6.调整继承
       7.关联的设计
                                   
    八、面向对象的实现

    (一)程序设计语言

       1.选择面向对象语言
       采用面向对象方法开发软件的基本目的和主要优点是通过重用提高软件的生产率。因此,应该优先选用能够最完善、最准确地表达问题域语义的面向对象语言。

       在选择编程语言时,应该考虑的其他因素还有:对用户学习面向对象分析、设计和编码技术所能提供的培训操作;在使用这个面向对象语言期间能提供的技术支持;能提供给开发人员使用的开发工具、开发平台,对机器性能和内存的需求,集成已有软件的容易程度。

       2.程序设计风格
       (1)提高重用性。
       (2)提高可扩充性。
       (3)提高健壮性。

    (二)类的实现

       在开发过程中,类的实现是核心问题。在用面向对象风格所写的系统中,所有的数据都被封装在类的实例中。而整个程序则被封装在一个更高级的类中。在使用既存部件的面向对象系统中,可以只花费少量时间和工作量来实现软件。只要增加类的实例,开发少量的新类和实现各个对象之间互相通信的操作,就能建立需要的软件。

       一种方案是先开发一个比较小、比较简单的来,作为开发比较大、比较复杂的类的基础。

       (1)“原封不动”重用。
       (2)进化性重用。
       一个能够完全符合要求特性的类可能并不存在。
       (3)“废弃性”开发。
       不用任何重用来开发一个新类。
       (4)错误处理。
       一个类应是自主的,有责任定位和报告错误。

    (三)应用系统的实现

       应用系统的实现是在所有的类都被实现之后的事。实现一个系统是一个比用过程性方法更简单、更简短的过程。有些实例将在其他类的初始化过程中使用。而其余的则必须用某种主过程显式地加以说明,或者当作系统最高层的类的表示的一部分。

       在C++和C中有一个main( )函数,可以使用这个过程来说明构成系统主要对象的那些类的实例。

    (四)面向对象测试

       (1)算法层。
       (2)类层。
       测试封装在同一个类中的所有方法和属性之间的相互作用。
       (3)模板层。
       测试一组协同工作的类之间的相互作用。
       (4)系统层。
       把各个子系统组装成完整的面向对象软件系统,在组装过程中同时进行测试。

    九、面向对象和基于对象的区别

          很多人没有区分“面向对象”和“基于对象”两个不同的概念。面向对象的三大特点(封装,继承,多态)却一不可。通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点。而“多态”表示为父类类型的子类对象实例,没有了继承的概念也就无从谈论“多态”。现在的很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。“面向对象”和“基于对象”都实现了“封装”的概念,但是面向对象实现了“继承和多态”,而“基于对象”没有实现这些,的确很饶口。

          从事面向对象编程的人按照分工来说,可以分为“类库的创建者”和“类库的使用者”。使用类库的人并不都是具备了面向对象思想的人,通常知道如何继承和派生新对象就可以使用类库了,然而我们的思维并没有真正的转过来,使用类库只是在形式上是面向对象,而实质上只是库函数的一种扩展。

          面向对象是一种思想,是我们考虑事情的方法,通常表现为我们是将问题的解决按照过程方式来解决呢,还是将问题抽象为一个对象来解决它。很多情况下,我们会不知不觉的按照过程方式来解决它,而不是考虑将要解决问题抽象为对象去解决它。有些人打着面向对象的幌子,干着过程编程的勾当。

    展开全文
  • 面向对象的基本概念

    千次阅读 2007-10-30 11:57:00
    面向对象其实是现实世界模型的自然延伸。现实世界中任何实体都可以看做是对象对象之间通过消息相互作用。另外,现实世界中任何实体都可归属于某类事物,任何对象都是某一类事物的实例。如果说传统的过程式编程语言...
    面向对象其实是现实世界模型的自然延伸。现实世界中任何实体都可以看做是对象。对象之间通过消息相互作用。另外,现实世界中任何实体都可归属于某类事物,任何对象都是某一类事物的实例。如果说传统的过程式编程语言是以过程为中心、以算法为驱动的话,面向对象的编程语言则是以对象为中心,以消息为驱动。用公式表示,过程式编程语言为:程序=算法+数据;面向对象编程语言为:程序=对象+消息。

    所有面向对象编程语言都支持3个概念,即封装、多态性和继承.现实世界中的对象均有属性和行为,映射到计算机程序上,属性则表示对象的数据,行为表示对象的方法(其作用是处理数据或同外界交互)。所谓封装,就是用一个自主式框架把对象的数据和方法连在一起形成一个整体。可以说,对象是支持封装的手段,是封装的基本单位。类描述了一组有相同特性(属性)和相同行为(方法)的对象。在程序中,类实际上就是数据类型,例如,整数、小数等。整数也有一组特性和行为。面向过程的语言与面向对象的语言的区别就在于,面向过程的语言不允许程序员自己定义数据类型,而只能使用程序中内置的数据类型。而为了模拟真实世界,为了更好地解决问题,我们需往往要创建解决问题所必需的数据类型。

    对象与实例有什么区别?
    答案:对象和实例从宏观的角度看,区别是:对象是同类事物的一种抽象表现形式,而实例是对象的具体化,一个对象可以实例化很多实例,对象就是一个模型,实例是照着这个模型生产的最终产品。实际上就是这样,一个对象可以实例化N个实例。就像根据一个模型可以制造多个实际的产品一样。
    从内存分配的角度来看,对象是保存在堆中的,而实例是存储在栈中的,实例其实只是对象的一个引用,也就是指向对象的指针。

    面试例题3:声明与定义之间的区别是什么?在Java里声明和定义能否分开?
    解析:
    声明:一种把一个名称引入或者重新引入到某个作用域的构造。
    定义:它也是一种声明,但该声明必须给出被声明实体的细节。
    对于变量而言,这里的细节是指:为被声明实体保留存储空间。
    对于class类型和函数定义而言,指的是包含有一对花括号内容的声明。
    对于外部变量而言,指的是前面没有关键字extern或者在声明时就进行初始化。
    变量的声明有以下两种情况。
    一种是需要建立存储空间的。例如,int a 在声明的时候就已经建立了存储空间。
    另一种是不需要建立存储空间的,例如,extern int a。其中,变量a是在别的文件中定义的。前者是“定义性声明(defining declaration)”,或者称为“定义(definition)”,而后者是“引用性声明(referencing declaration)”。从广义的角度来讲,声明中包含着定义,但是并非所有的声明都是定义,例如int a,它既是声明,同时又是定义。然而对于 extern a来讲,它只是声明不是定义。在一般的情况下我们常常这样叙述,把建立空间的声明称为“定义”,而把不需要建立存储空间的声明称为“声明”。很明显在这里指的声明的范围是比较窄的,也就是说非定义性质的声明。
    答案:
    变量的定义和声明的区别在于是否分配内存,如果分配内存就是定义,否则就是声明。
    类中的变量只是声明而不是定义,因为它只是类声明的一部分。不同于变量的定义,类的定义是一种新的类型的定义,只有实例化后才会分配内存。所以类成员变量只是声明而不是定义。
    在Java中,利用Interface,也可以将声明和实现分开。如下所示。
      //MyInterface.java  
      public   interface   MyInterface 
     {  
            void   method();  
      }  
       
      //MyImpl.java  
      public   class   implements   MyInterface 
     {  
            public   void   method()
            {  
                  //……
            }  
      }  
    面试例题4:Which is incorrect about the class?(关于类的描述下面哪个是错误的?)[金山公司2005年面试题]
    A.A class is a blueprint to objects.
    B.We use the keyword class to create a class construct.
    C.Once a class is declared, the class name becomes a type name and
    can be used to declare variables.
    D.The class is same as the struct, and there are no different between
    class and struct.
    解析:这道题的考点是类的概念。
    答案:D
    面试例题5:Which is incorrect about the OOP?(下面关于面向对象技术的叙述哪个是错误的?)[金山公司2005年面试题]
    A.The central idea of OOP is to build programs using software objects.
    B.The OOP focuses mainly on the step-by-step procedure as procedure-
    oriented programing.
    C.The OOP offers many advantages: simplicity,modularity,modifiability,
    extensibility, and so on.
    D.The key concept of object orientation is the attachment of procedure
    to data.
    解析:OOP的概念面试例题。面向对象和面向过程不能混为一谈。
    答案:B,D


    11.2  类和对象
    面试例题1:以下代码编译时会产生错误的是______。[Trend公司2005年面试题]
    class reverseIt4
    {
     
      public static void main(String[] args)
      {
         EnclosingClass jb2;                  //-----1
         System.out.println(jb2.m);     //-----2
      }
    }
    class EnclosingClass               //--------3
    {
      public int m = 6;
       class InnerClass               //-------4
      {
         int msquare;
         InnerClass()
         {
            msquare = m*m;
         }
      }
    }
    A.语句1          B.语句2          C.语句3          D.语句4
    解析:语句3和语句4显然是正确的,尽管它们的描述不是那么规范(存在一个类中的类)。语句1声明了一个类,但是没有做定义,于是问题就出现了。声明好比只是告诉编译器有一个人,但是如果不定义,这个人就是个抽象的人,没有身高、体重、年龄、职业的“空”人。所以定义对象必须在声明的同时给它定义。正确的程序如下。
    class reverseIt4
    {
     
      public static void main(String[] args)
      {
         EnclosingClass jb = new EnclosingClass();
        
          System.out.println(jb.m);
        
      }
    }
    class EnclosingClass
    {
      public int m = 6;
       class InnerClass
      {
         int msquare;
         InnerClass()
         {
            msquare = m*m;
         }
      }
    }
    答案:该题是问编译在哪儿出现问题,尽管问题出在1处,但编译器不会发现,编译器只有在2处才会发现问题。所以答案选B。
    面试例题2:Object是所有类的父类,任何类都默认继承Object。Object类到底实现了哪些方法?
    答案:
    1.clone方法
    保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
    2.getClass方法
    final方法,获得运行时类型。
    3.toString方法
    该方法用得比较多,一般子类都有覆盖。
    4.finalize方法
    该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
    5.equals方法
    该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
    6.hashCode方法
    该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
    一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
    7.wait方法
    wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
    调用该方法后当前线程进入睡眠状态,直到以下事件发生。
    (1)其他线程调用了该对象的notify方法。
    (2)其他线程调用了该对象的notifyAll方法。
    (3)其他线程调用了interrupt中断该线程。
    (4)时间间隔到了。
    此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
    8.notify方法
    该方法唤醒在该对象上等待的某个线程。
    9.notifyAll方法
    该方法唤醒在该对象上等待的所有线程。


    11.3  嵌套类
    面试例题1:请说明static nested class和inner class的不同。
    答案:
    1.nested(嵌套)class(一般是C++的说法)
    nested class是合成型聚集关系(Composite Aggregation)的另一种表达方式,也就是说nested class也可以用Aggregation表达出来。但是,nested class更加精确地表达了一种专用的、紧耦合的关系,尤其在代码生成时,nested class在Java中映射成inline class。比如,计算机专用开关电源类可以作为计算机类的nested class,但是,电池组类就不一定适合作为计算机类的nested class,因为,电池组类表述的是一个过于通用的对象,可能还被包含(Aggregation)于模型中的其他设备对象。class A nested in class B,则说明A是一个nested class,一般A是用来完成B中的某种重要功能的。
    2.inner class(一般是Java的说法)
    Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。
    静态内部类(inner class)意味着:创建一个static内部类的对象,不需要一个外部类对象;不能从一个static内部类的一个对象访问一个外部类对象。
    面试例题2:关于下面类的定义,以下哪种说法是正确的?[研华科技2005年11月面试题]
     public class Droitwich{
            class one{
                    private class two{
                            public void main(){
                            System.out.println("two");
                            }
                    }
            }
    }
    A.此代码不能编译成功,因为该类嵌套了不止一层
    B.此代码不能编译通过,因为class two是私有的
    C.此代码可以编译通过,并且在运行的时候输出字符串two
    D.此代码编译没有错误
    解析:
    内部类或嵌套类在类层级上没有限制,所以选项A是错误的。
    内部类可以是私有类,所以选项B也是错误的。
    选项C的main方法不是public static void main的,并且假设命令行是java Droitwich,它不能在任何地方被调用。
    答案:D


    广义接口的真正意义是在类的继承中体现多态的功能,这种接口又被称为抽象类接口。
    狭义接口是指特定的函数集合,一般是用interface(Delphi)声明的,它表示一个方法集合,这个集合被称为一个命名接口。一个命名接口中的方法必须在一个类中实现后才能被使用,一个类继承实现一个接口,称为这个类实现了该接口,一个接口可以被多个类实现,一个类也可以继承多个接口,这样就形成了一种灵活的接口调用方式,从而实现更加灵活和节省资源的多态。
    从上述认识来看,接口实际上是结合着多态而来的,它的最大的任务就是实现多态。而多态又是面向对象最精华的理论,掌握了多态,也就掌握了面向对象的精髓。但掌握多态必须先理解和掌握接口,只有充分理解接口的意义,才能更好地应用多态。

    面试例题1:下面哪一项说法是正确的?
    A.在一个子类中一个方法不是public的就不能被重载
    B.覆盖一个方法只需要满足相同的方法名和参数类型就可以了
    C.覆盖一个方法必须需要相同的方法名参数和返回类型
    D.一个覆盖的方法必须有相同的方法名、参数名和参数类型
    解析:
    对于在同一可访问区内被声明的几个具有不同参数列(参数的类型、个数、顺序不同)的同名函数,程序会根据不同的参数列来确定具体调用哪个函数,这种机制叫重载,重载不关心函数的返回值类型。覆盖是指派生类中存在重新定义的函数,其函数名、参数列、返回值类型必须同父类中的相对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体(花括号中的部分)不同,当派生类对象调用子类中该同名函数时会自动调用子类中的覆盖版本,而不是父类中的被覆盖函数版本,这种机制就叫做覆盖。
    成员函数被重载的特征如下。
    (1)相同的范围(在同一个类中);
    (2)函数名字相同;
    (3)参数不同;
    (4)virtual关键字可有可无。
    覆盖的特征如下。
    (1)不同的范围(分别位于派生类与基类);
    (2)函数名字相同;
    (3)参数相同;
    (4)基类函数必须有virtual关键字。
    答案:C
    面试例题2:下面的说法中哪项是正确的?
    A.静态方法不能被覆盖成非静态的方法
    B.静态方法不能被声明成私有的
    C.私有的方法不能被重载
    D.一个重载的方法在基类中不通过检查不能抛异常
    解析:JDK 1.1版本会发布这样一个提示信息:静态的方法不能被覆盖。选项 B和C的说法并不合理,没有合理的理由来说静态的方法不能被声明成私有的,或私有的方法不能被重载。选项D是对于一个覆盖方法异常限制的混杂版本来说的。
    答案:A
    面试例题3:给定下面的代码。
    class Base {}
    class Agg extends Base{
            public String getFields(){
             String name =  "Agg";
            return name;
            }
    }
    public class Avf{
    public static void main(String argv[]){
            Base a = new Agg();
            //Here
            }
    }
    What code placed after the comment //Here will result in calling the getFields method resulting in the output of the string "Agg"?(下面哪个选项的代码替换到//Here,会调用getFields方法使输出结果输出字符串“Agg”?)
    A.System.out.println(a.getFields());
    B.System.out.println(a.name);
    C.System.out.println((Base) a.getFields());
    D.System.out.println( ((Agg) a).getFields());
    解析:Base类型要引用Agg类的实例需要把Base类显示转换为Agg类,然后调用Agg类中的 getFields()方法。如果a是Base类的一个实例的话,它要调用getFields()方法,那此方法在Base类中是不存在的,必须把a转换为Agg类的一个实例,这样才可以调用它里面的方法。
    答案:D
    面试例题4:如果在下列代码中的Here处添加一段代码,问哪一个选项不能通过编译[Trend公司2005年10月面试题]
    public class Upton{
    public static void main(String argv[]){    
            }
            public void amethod(int i){}
            //Here
           
    }
    A.public int amethod(int z){}
    B.public int amethod(int i,int j){return 99;}
    C.protected void amethod(long l){}
    D.private void anothermethod(){}
    解析:选项A不能通过编译。一个方法是显式地返回一个int值的方法,另一个是在同一个类中上述方法的一个重定义。方法中参数从i换做z对一个方法并没有任何影响。一个方法不能在同一个类中被覆盖。
    答案:A
    面试例题5:下面代码的输出结果是多少?[Trend公司2005年10月面试题]
    class A {
        public static void prt() {
            System.out.println("1");
        }
        public A() {
            System.out.println("A");
        }
    }
    public class B extends A {
        public static void prt() {
            System.out.println("2");
        }
        public B() {
            System.out.println("B");
        }
        public static void main(String[] args) {
            A a = new B();
            a = new A();
        }
    }
    解析:每新建一个对象,都会产生一个构造函数,因为产生构造函数的顺序是A,B,A,所以结果是A,B,A。
    答案:A,B,A
    面试例题6:下面代码的输出结果是多少?[Trend公司2005年10月面试题]
    class Parent {
    protected String value = "123";
    public String getValue() {
          return value;
    }
    }
    public class Child extends Parent {
    protected String value = "456";
    }
    解析:父类里的东西也可以理解成你自己的东西。也就是说在程序里面有两个value,一个是123,另一个是456。而现在要输出的是父类里面的那个value,所以就是123。原因是在输出语句中使用的是getValue()方法,而这个方法就是父类里面的方法。它的返回值是父类里面定义的value,从父类继承来的没有被子类覆盖的方法操作的是继承于父类的被隐藏的变量,也就是123。
    答案:123




    12.2  Super
    面试例题1:以下代码的输出结果是下列哪个选项?[Sun公司2005年面试题]
    class Base{
    Base(){
            System.out.println("Base");
            }
    }
    public class Checket extends Base{
    Checket(){
           System.out.println("Checket"); 
           super();
           
            } 
    public static void main(String argv[]){
         Checket c = new Checket();
          //  super();
            }
         
    }    
    A.Compile time error
    B.Checket followed by Base
    C.Base followed by Checket
    D.runtime error
    解析:这是一个考查super构造函数的面试例题。子类的构造函数如果要引用super的话,必须把super放在函数的首位,不然会出现这样的报错:
    Checket.java:10: call to super must be first statement in constructor
           super();
    如果一定要引用super构造函数,则必须把super()放在前面,代码如下。
    class Base{
    Base(){
            System.out.println("Base");
            }
    }
    public class Checket extends Base{
    Checket(){
          
            super();
            System.out.println("Checket"); 
            } 
    public static void main(String argv[]){
            Checket c = new Checket();
          //  super();
            }
         
    }    
    答案:会出现编译报错,选项A
    面试例题2:Java里在类中用super调用父类构造函数时,为什么调用语句必须是子类的第一条语句?[Siemens公司2005年面试题]
    答案:如果想用super继承父类构造的方法,但是没有放在第一行的话,那么在super之前的语句,肯定是为了满足自己想要完成某些行为的语句,但是又用了super继承父类的构造方法。那么以前所做的修改就都回到以前了,就是说又成了父类的构造方法了。如下面的程序所示。
    class Father
    {
    public Father()
    {String name=null;
    int age=0;}
    }
    class Son extends Father
    {
    public Son()
    {String name="学生";
    super();
    }
    }    
    扩展知识(Java中的super类)
    在Java 中,有时还会遇到子类中的成员变量或方法与超类(有时也称父类)中的成员变量或方法同名。因为子类中的成员变量或方法名优先级高,所以子类中的同名成员变量或方法就隐藏了超类的成员变量或方法,但是我们如果想要使用超类中的这个成员变量或方法,就需要用到super。请看下面的类。
    class Country
       {
        String name;
        void value()
        {
         name="China";
        }
       }
    在下面的子类中,子类的成员变量和方法隐藏了超类的成员变量name和方法value()。
    class City extends Country
        String name;
        void value()
        {
         name="Hefei";
         super.value();
         System.out.println(name);
         System.out.println(super.name);
       }
    为了在子类中引用超类中的成员变量name和方法value(),在代码中使用了super、super.name和super.value(),所以显示的结果为:
    Hefei
    China
    如果想要使用超类的构造函数,则应当使用super(参数列表)的形式。
    面试例题3:给定下面的代码,哪个选项在替代“//Here”后可以被编译并且改变变量oak的值?
    class Base{
    static int oak=99;
    }
    public class Doverdale extends Base{
    public static void main(String argv[]){
            Doverdale d = new Doverdale();
            d.amethod();
            }
            public void amethod(){
            //Here
            }      
    }
    A.super.oak=1;
    B.oak=33;
    C.Base.oak=22;
    D.oak=50.1;
    解析:因为变量oak被声明是静态的,如果它存在只能有一个本体,则它可以通过本类的名字或者通过定义本类的任何一个实例被改变。
    答案:A、B、C
    面试例题4:当编译和运行下列代码时会发生下列哪种情况?
    class Base{
    Base(){
            System.out.println("Base");
            }
    }
    public class Checket extends Base{
    public static void main(String argv[]){
            Checket c = new Checket();
            super();
            }
    Checket(){
            System.out.println("Checket"); 
            }      
    }
    A.Compile time error
    B.Checket followed by Base
    C.Base followed by Checket
    D.runtime error
    解析:
    用Sun的JDK运行会出现下列出错信息。
    "Only constructors can invoke constructors"
    Checket作为一个构造方法应该在调用时从最老的祖先类开始向下调用,调用super会引起程序在编译和运行时间上的错误。
    Java中的关键字super:调用父类的属性,一个类中如果有int x属性,如果其子类中也定义了int x属性的话,在子类中调用父类的x属性时应用super.x = 6,表示该x是引用的父类的属性,而要表示子类中的x属性的话,使用this.x。
    this和super:在Java中,this通常指当前对象,super则指父类的对象。若想要引用当前对象的某种东西,比如当前对象的某个方法,或当前对象的某个成员,便可以利用this来实现这个目的。当然,this的另一个用途是调用当前对象的另一个构造函数。如果想引用父类的某种东西,则非super莫属。
    Java里在子类中用super调用父类构造函数时,调用函数必须放在子类的第一条语句的位置,如果想用 super继承父类构造的方法,但是没有放在第一行的话,那么在super之前的语句,也许是为了满足自己想要完成某些行为的语句,但是又用了super 继承父类的构造方法,以前所做的修改就都回到以前了,也就是说又成了父类的构造方法了。
    答案:A


    12.3  this
    面试例题1:下面程序的结果是什么?[Trend公司面试题]
    class Tester
    {
    int var;
    Tester(double var)
    {
          this.var = (int)var;
         
    }
    Tester(int var)
    {
          this("hello");
    }
    Tester(String s)
    {
          this();
        System.out.println(s);
    }
    Tester()
    {
        System.out.println("good-bye");
    }
    public static void main(String[] args)
    {
          Tester t = new Tester(5);
    }
    }
    答案:
    good-bye
    hello
    扩展知识(变量的内存分配情况)
    在Java 中有两个非常特殊的变量:this和super,这两个变量在使用前都是不需要声明的。this变量使用在一个成员函数的内部,指向当前对象,当前对象指的是调用当前正在执行方法的那个对象。super变量是直接指向超类的构造函数,用来引用超类中的变量和方法。因此它们都是非常有用的变量。下面介绍一下 this的使用方法。
    先看下面的一段代码。
    class PersonInformation
      {
       String name,gender,nationality,address;
       int age;
       void PersonInformation(String p_name,String p_gender,String
           p_nationality,String p_address,int p_age)
       {
        name=p_name;
        gender=p_gender;
        nationality=p_nationality;
        address=p_address;
        age=p_age;
       }
      }
    在PersonInformation()函数中这个对象的方法提示可以直接访问对象的成员变量,而且在同一个范围中,定义两个相同的名字的局部变量是不允许的。如果确实想使类的成员变量与方法的参数或方法自己定义的局部变量同名的话,就需要想一种方法使成员变量与跟它同名的方法参数或局部变量区分开来,这就要使用到this变量。下面改写一下上面的代码,使 PersonInformation类的构造函数的每个参数都有与对象成员变量相同的名字,而成员变量的初值由参数给出。
    class PersonInformation
       {
        String name,gender,nationality,address;
        int age;
        void PersonInformation(String name,String gender,String
            nationality,String address,int age)
        {
        this.name=name;
        this.gender=gender;
        this.nationality=nationality;
        this.address=address;
        this.age=age;
        }
       }
    从上例中可以看出,该构造函数中必须使用this。this在方法体中用来指向引用当前正在执行方法的那个对象实例。this变量的类型总是为包含前执行方法的类。在上例中,我们要区别参数 name和成员变量name,写成name=name显然是不允许的。在参数或局部变量名与类成员变量名相同的时候,由于参数或局部变量的优先级高,这样在方法体中参数名或局部变量名将隐藏同名的成员变量,因此,为了指明成员变量,必须使用this显式地指明当前对象。
    有时候会遇到这种情况,全面地访问当前对象,而不是访问某一个个别的实例对象,此时也可以使用this,并利用Java中的toString()方法(它能够返回一个描述这个对象的字符串)。如果把任何一个对象传递到System.out.println方法中,这个方法调用这个对象的toString方法,并打印出结果字符串,所以,可以用 System.out.println(this)方法来打印出固有参数的当前状态。
    this还有一个用法,就是构造函数的第一个语句,它的形式是this(参数表),这个构造函数就会调用同一个类的另一个相对的构造函数。请看下面的例子。
    class UserInfo
    {
       public UserInfo(String name)
       {
        this(name,aNewSerialNumber);
       }
       public Userinfo(String name,int number)
       {
        userName=name;
        userNumber=number;
       }
    }
    如果调用UserInfor newinfotable = new UserInfo("Wayne Zheng"),就会自动调用UserInfo(String name,int number)构造函数。
    可见,熟练掌握this在Java程序设计过程中是非常重要的。
    面试例题2:以下代码的运行结果是     。[Advantech公司2005年12月面试题]
    class Base{
       int i;
       Base(){
       add(1);
       System.out.println(i);
     }
     void add(int v){
        i+=v;
        System.out.println(i);
     }
     void print(){
        System.out.println(i);
       }
    }
    class MyBase extends Base{
       MyBase(){
        add(2);
     }
       void add(int v){
         i+=v*2;
         System.out.println(i);
       }
    }
    public class TestClu {
      public static void main(String[] args) {
     
        go(new MyBase());
      //System.out.println();
     }
        static void go(Base b){
        b.add(8);
       //b.print();
     }
    }
    A.12                   B.11                   C.22                   D.21
    解析:
    程序流程是这样的:在主函数中,首先执行 new MyBase(),在这个过程中,子类会首先调用父类的构造函数;在父类的构造函数Base()中执行add()方法。这里需要注意,这个add方法由于是在新建MyBase对象时调用的,将会首先查找MyBase类中是否有此方法。所以,Base()函数中的add(1)实际上是:
    void add(int v)
           {
         i+=v*2;
         System.out.println(i);
       }
    此时i的值即为2。在打印两个2之后,父类构造函数执行完毕,执行子类的构造函数,即MyBase(),这里的add(2)当然也是子类的。i的值就变为了6。
    最后执行go函数,i即为22。
    答案:C
    展开全文
  • Oracle 概念(Oracle 10.2)5、模式对象本章描述了用户模式中包含的不同类型的数据库对象。本章保安下列内容:u 模式对象介绍u 表概述u 视图概述u 实体化视图概述u 维度概述u 序列生成器概述u 同义词概述u...

     

    Oracle 概念(Oracle 10.2)

    5、模式对象

    本章描述了用户模式中包含的不同类型的数据库对象。

    本章保安下列内容:

    模式对象介绍

    表概述

    视图概述

    实体化视图概述

    维度概述

    序列生成器概述

    同义词概述

    索引概述

    索引组织表概述

    应用领域索引概述

    聚集概述

    Hash聚集概述

    模式对象介绍

    模式(schema)是数据的逻辑结构或者说模式对象的汇总。一个模式对应一个数据库用户,并且名字和数据库用户名相同。每个用户都有一个单独的模式。模式对象可以通过SQL创建(DDL)和操作(DML),包含下列类型:

    聚集

    数据库链

    数据库触发器

    维度

    外部过程库

    索引和索引类型

    Java类、Java资源和Java源代码

    实体化视图和实体化视图日志

    对象表、对象类型和对象视图

    操作符

    序列

    存储函数、过程和包

    同义词

    表和索引组织表

    视图

    还有一些类型的对象可以保存在数据库中,也可以通过SQL创建和操作,但是不包含在模式中:

    上下文(Contexts)

    目录(Directory)

    概要文件(Profile)

    角色(Role)

    表空间(Tablespaces)

    用户(User)

    模式对象是数据的逻辑存储结构。数据对象和磁盘上保存其信息的物理文件并不一一对应。Oracle在数据库的一个表空间上保存模式对象。每个对象的数据物理的保存在表空间的一个或者多个数据文件上。对某些对象如表、索引、聚集来说,你可以指定在表空间的数据文件上Oracle可以分配多大的磁盘空间来存储这个对象。

    模式和表空间没有什么联系:一个表空间可以包换来自不同模式的对象,模式对象可以包含在不同的表空间上。

    图5-1描述了对象、表空间、数据文件之间的关系。

    图5-1 模式对象、表空间和数据文件

    表概述

    表是Oracle数据库内数据存储的基本单位。数据是按照行和列来存储。你用一个表名(比如employees)、一系列列来定义表。你为每列指定一个列名(比如employee_id,last_name和job_id等),一个数据类型(比如VARCHAR2,DATE,NUMBER)和一个宽度。宽度可以是数据类型比如日期预先定义好的。如果列是NUMBER类型,定义范围和精度就可以了。行是关联到一个记录的列信息的集合。

    你可以指定表中每个列的规则。这些规则叫做完整性约束条件。NOT NULL就是一个完整性约束的例子。这个约束条件要求这列的每一行都包含一个值。

    你还可以指定表列在保存在数据文件之前将数据加密。加密阻止了越过数据库访问控制来直接使用操作系统工具查看数据文件的现象。

    在你创建表之后,使用SQL语句插入行数据。表的数据就可以使用SQL查询、删除和更新。

    图5-2描述了一个实例表

     

    图5-2 EMP表

    表数据如何保存

    当你创建表时,Oracle在一个表空间上自动分配一个数据段来保存表将来的数据。你有两种方式可以控制一个表数据段的分配和使用:

    你可以通过设定数据段的存储参数来控制分配给数据段的空间大小

    通过设置组成数据段的区段的数据块的参数PCTFREE和PCTUSED来控制块的空闲空间的使用。

    对于聚集表来说,Oracle在针对聚集表创建的数据段上保存数据,而不是在表空间的上分配数据段保存数据。聚集表创建和修改时不能指定存储参数。聚集的存储参数设置控制了聚集中中所有表的存储。

    表的数据段(或者聚集数据段,针对聚集表)可以创建在表拥有者的默认表空间上,或者在CREATE TABLE语句中指定。

    行格式和大小

    Oracle将一个包含至多256列的数据库行保存在一个或多个行片中。如果整个行能够插入一个数据块中,然后Oracle会保存这个行在一个行片中。虽然如此,如果所有的行数据不能插入一个数据块或者对一个现存行的更新造成行数据超出了它的数据块,然后Oracle会使用多个行片保存行。一个数据块通常一行只包含在一个行片中。当Oracle必须在多个行片中保存行时,它就是跨块链接的(行链接)。

    当一个表拥有多余255个列,255之后的列的数据就会在同一块中链接(如果不超出块的话)。这个叫做块内部链接。行片链接是通过片的ROWID来链接起来的。通过块内部链接,用户可以从同一块中得到所有数据。如果行可以放在一个块中,用户不会感觉到I/O性能的影响,因为取得额外的行(255之后的行)不需要额外的I/O操作。

    每个行片,无论链接还不是没有链接,都包含一个行首部(row header)和部分或全部行数据。单独的行可能跨越行片或者数据块。图5-3描述了行片的格式。

    图5-3 行片的格式

    行首部在数据的前面,包含如下信息:

    行片

    链接(只针对行片链接)

    行片的列

    聚集键(只针对聚集数据)

    完全属于一个数据块的行至少拥有3个字节的行首部(row header)。在行首部信息之后,每个行包含列宽度和数据。列宽度需要在列数据之前保存,少于250个字节的列使用1个字节保存、多于250字节的列使用3个字节保存。列数据需要的空间依赖于列类型。如果列类型是变长的,那么保存这个值的空间需要随着数据更新增长或收缩。

    为节省空间,一个null列只保存列长度(0)。Oracle不保存null列的数据。而且,对于尾部的null列来说,Oracle甚至都不保存列长度。

    聚集行包含非聚集行同样的信息。除此之外,它们还包含指向他们所属的聚集键信息。

        行片的rowid

    Rowid标识了每个行片的位置或地址。分配的rowid会一直保留,直到关联的行被删除或者使用Oracle工具导入导出为止。对聚集表来说,如果行的聚集键值改变,行会保留同样的rowid,但是会增加一个指向新值的rowid指针。

    因为rowid对于行片的生命周期来说是一直保留的,例如SELECT,UPDATE和DELETE的SQL语句使用ROWID非常有用。

        列顺序

    对一个给定的表来说,所有行的列顺序都是一致的。列的保存顺序通常和语句CREATE TABLE中显示的是一样的,但也不是必然的。例如,如果一个表拥有一个LONG数据类型的列,Oracle总是在最后保存这个列。而且如果修改一个表来增加一列,新列就变成最后保存的列。

    通常来说,将经常为空的列保存在最后就可以节省空间。但是要注意的是,如果创建表包含一个LONG列,这个频繁为空的列就不能放在最后了。

    表压缩

    Oracle的表压缩特性通过减少数据块中重复值来压缩数据。数据块(磁盘页)中保存的压缩数据是自包含的。就是说,一个数据块中需要重新创建解压缩的所有数据信息对本数据块是可用的(一个块上的信息需要解压缩才能读取,但同样的信息在另一块上不需要)。一个块上的所有行和列的重复值都在块开始的地方保存一次,这个地方也叫块的符号表。这些(重复)值出现的地方都替代为指向符号表的链接。

    除了开始的符号表之外,压缩数据库块看起来和通常数据库块非常类似。适用于通常数据库块的所有数据库特性和函数也适合压缩数据库块。

    包括表和实体化视图的数据库对象都可以压缩。对于分区表来说,你可以选择压缩部分或者全部分区。压缩属性可以用在表空间、表或者分区表。如果在表空间级别声明压缩属性,那么其上创建的所有表默认都是压缩的。你可以修改一个表(或者表空间、分区表)的压缩属性,但只对新加入表的数据有效。因此,一个表或者分区可能同时包含压缩块和正常块。这样确保数据大小不能因为压缩而增加;在压缩会增加块使用时,块不会使用压缩。

    使用表压缩

    数据批量插入和批量装载时会导致压缩。包括如下操作:

    SQL *Loader使用直接路径

    CREATE TABLE和AS SELECT语句

    并发INSERT(或使用提示APPEND串行INSERT)语句

    数据库的已有数据可以通过ALTER TABLE和MOVE子句移动到压缩结构来压缩。这个操作会在表上加独占锁,从而会阻止任何更新和数据装载,直到压缩完成为止。如果客户不能接受这些,那么可以使用Oracle在线重定义工具(DBMS_REDEFINITION PL/SQL包)。

    数据压缩在大部分数据类型上都可用,除了LOB的变体和源于LOB的数据类型,比如保存数组数据VARRAY类型保存存在CLOB中的XML数据类型。

    压缩表或者压缩分区可以和其他Oracle表或分区一样的修改。例如,数据可以使用INSERT、UPDATE和DELETE语句更新。无论如何,不使用批量插入或批量装载技术修改的数据是没有压缩的。删除压缩数据和删除非压缩数据一样快。插入新数据也一样的快,因为常规的INSERT语句不使用压缩;只有在批量装载才会压缩。更新压缩数据在某些情况下会慢一些。由于这些原因,压缩更适合数据仓库应用程序,而不是OLTP应用程序。只读或者很少改变的部分数据(比如历史数据)应该使用压缩格式。

    值NULL表示值不存在

    Null代表行中的一列不存在值。Null代表丢失的、未知的或者不适用的数据。Null值不应该用来代表任何其他值,比如0。一个列如果定义了PRIMARY KEY和NOT NUL完整性约束就不允许null值,这时候任何行的列都必须指定值才能插入。

    Null值在有值的列之间会保存。这时候,它需要保存列长度(0)。

    行的尾null列不需要存储空间,因为后面的新行首部就说明了前面的行最后的列是null。例如,如果最后3列为null,这些列就不会保存任何信息。在设计表的列时,null概率较高的列应该定义在后面,这样可以节省空间。

    null值和其他值的比较结果既不是真也不是假,是未知。在SQL中标识null,需要使用IS NULL。使用NVL函数可以将null值转换为非null值。

    Null值是不能索引的,除非聚集键列值为null或者索引使用了位图索引。

    列默认值

    你可以指定表一个列的默认值,这样插入新行的时候可以忽略这个行值,或者可以使用DEFAULT关键字,这时候会自动提供默认值。默认值工作起来就如同INSERT语句指定了默认值一样。

    默认文字或者表达式的数据类型必须符合或者可以转换为列的数据类型。

    如果一列没有明确指定默认值,默认值就是null。

    默认值插入和完整性约束

    在包含默认值的行插入之后会启动完整性约束。例如,在图5-4中,一个插入到emp表的行不包括雇员的部门号的值。因为没有提供部门号的值,Oracle在deptno列中插入了默认值20.。插入默认值之后,Oracle检查定义在deptno列的外键完整性约束。

    图5-4 列默认值

    分区表

    分区表允许你将你的数据分成更小的容易的管理的叫做分区的部分,甚至还可以包含子分区。索引可以按照类似的方式分区。每个分区可以单独管理,可以独立于其他分区进行操作,这样就针对可用性和性能方面提供了更好的调整结构。

    嵌套表

    你可以创建一个表,表中的列类型是另外一个表。就是说,表可以嵌套在另一个表中作为一个列的值。Oracle数据库服务器并不是把嵌套表保存在父表的行里,而是将一个存储表和嵌套表行关联。父表行包含一个唯一标识符来关联嵌套表实例。

    临时表

    除了持久表,Oracle还可以创建临时表来保存会话私有的数据,这些数据只在事务或会话期间保存。

    CREATE GLOBAL TEMPORARY TABLE语句可以创建一个事务型或会话型临时表。对于事务型临时表,在事务持续期内数据存在。对于会话型临时表,会话持续期间数据存在。临时表中的数据是会话独立的。每个会话只能看到和修改自己的数据。DML锁不能加到临时表的数据上。LOCK语句对临时表的数据没有影响,因为每个会话拥有它们的私有数据。

    会话型临时表的TRUNCATE语句删除当前临时表的数据。不能删除其他会话中使用同一个表的数据。

    临时表上的DML语句产生的数据改变不会产生重做日志。但是会产生数据的undo日志和undo日志的重做日志。会话结束时临时表的数据会自动删除,包括用户登出或者会话意外终止(比如会话或实例失败)。

    你可以使用CREATE INDEX语句来为临时表创建索引。临时表上的索引也是临时的,临时表上的索引数据也和临时表的数据一样在事务或者会话期间存在。

    你还可以创建同时访问临时表和持久表的视图。你还可以创建临时表的触发器。

    Oracle工具可以导入导出临时表的定义。但是,即使你使用ROWS子句也无法导出任何数据行。类似的,你可以复制历史表的定义,但是无法复制其数据。

    段分配

    临时表使用临时段。和持久表不同,临时表和他们的索引在他们创建时不会自动分配一个段。相反,段在第一个INSERT(或CREATE TABLE AS SELECT)语句执行时分配。这意味着在第一个INSERT之前执行SELECT,UPDATE,DELETE语句,表看起来是空的。

    你只有在没有会话绑定了临时表时可以执行DDL语句(ALTER TABLE,DROP TABLE,CREATE INDEX)。临时表在会话对其执行INSERT时和会话绑定,在使用TRUNCATE、会话终止或者对事务型临时表使用COMMIT和ROLLBACK表时解除绑定。

    事务末尾释放事务型临时表的段,会话末尾释放会话型临时表的段。

    父子事务

    事务型临时表可以被用户事务和他们子事务访问。但是,一个给定的事务型临时表不能被一个会话中两个事务同时访问,虽然它可以被不同会话中的事务访问。

    如果一个用户事务对临时表执行了INSERT语句,然后其所有子事务都不能使用这个临时表。

    如果一个子事务对临时表执行INSERT语句,然后在这个子事务的末尾,临时表的数据会消失。然后用户事务或者子事务可以访问临时表。

    外部表

    外部表访问外表资源的数据就如同它们是数据库中的表一样。你可以连接目标数据库并使用DDL(数据定义语言)创建元数据外部表。外部表的DDL由两个部分组成:一部分描述了Oracle列类型,另一部分(访问参数)描述了外部数据到Oracle数据列的映射。

    一个外部表不用于任何保存在数据库内部的数据。也不描述数据如何保存在外部资源中。相反,它描述了外部表层如何展现数据给服务器。外部表只是一个数据文件上的数据需要的访问驱动和外部表层的必要的转换,这样数据才能符合外部表定义。

    外部表是只读的;因此不允许任何DML操作,不能创建任何索引。

    访问驱动

    外部表环境中,数据装载指的是从外部表读取数据,然后装载到数据库内的表的动作。数据转储指的是从数据库中表读取数据和插入到外部表中。

    默认的外部表类型是ORACLE_LOADER,这让你可以可以从外部表读取数据并装载进数据库。Oracle还提供ORACLE_DATADUMP类型,这允许你转储数据(就是说,从数据库的表中读取数据,然后插入到外部表中),然后在数据库中重新装载它。

    外部表的定义使得数据源中的数据和定义分离,这样意味着:

    源文件包含的列可以多余或少于外部表中的列

    数据源中域的数据类型可以和外部表定义的列类型不同

    使用外部表装载数据

    外部表的主要作用是作为一个行来源将数据装载到数据库的一个实际表中。你创建外部表之后,你可以使用CREATE TABLE AS SELECT或者INSERT INTO ..... AS SELECT语句,使用外部表作为SELECT语句的来源。

    注意:你不能向外部表插入或者更新其中的数据;外部表是只读的。

    当你通过SQL语句访问外部表,外部表的域可以像正常表任何其他域一样使用。特别的是,你可以将域作为任何SQL内建函数、PL/SQL函数或Java函数的参数。这样你就可以处理外部数据的资源。对于数据仓库来说,你可以使用简单的类型转换来进行更多的复杂转换。你可以在数据库中使用这种机制来进行数据清理。

    外部表的并发访问

    一个外部表的元数据创建之后,你可以直接或者并行的方式使用SQL访问外部表。这样外部表就像一个视图一样,你可以使用外部表运行任何SQL而不需要将外部数据装入数据库。

    外部表的并行访问水平使用标准的并行提示(HINT)和PARALLEL子句。在外部表上使用并发可以并发的访问组成外部表的数据文件。单独文件是否可以并发访问依赖于访问驱动程序的实现和正在访问的数据文件属性(例如,记录格式)。

    视图概述

    视图是一个或多个表或者其他视图的数据的定制展示。一个视图将查询的输出作为一个表。因而,一个视图可以被认为是一个存储的查询或虚拟表。你可以在大部分可以使用表的地方使用视图。

    例如,employees表拥有几个列和一些行的信息。如果你想只使用其他的5列或者指定的行,然后你就创建这张表的视图,这样其他用户就可以直接访问。

    图5-5显示了一个叫做staff的视图,它来源于基表employees,需要注意的是视图只显示基表的5列数据。

    图5-5 一个视图实例

    因为视图来源于表,所以它们之间有类似的地方。例如,你可以像表一样定义1000个列的视图。你可以查询视图,在某些限制下还可以更新、插入和删除视图中的数据。视图上执行的操作实际上影响的是视图基表的数据,并且服从基表的完整性约束条件和触发器。

    你不能直接在视图上显示定义触发器,但你可以在视图引用的基表上定义。Oracle还支持视图上的逻辑约束。

    视图如何存储

    和表不同,视图并不分配存储空间,也不包含实际数据。相反,视图是一个查询的定义,是从视图引用的表中抽取数据的查询。这些表叫做基表(base table)。基表可以是表、也可以是视图(或者实体化视图)。因为视图基于其他对象,视图只需要在数据字典中存储视图的定义(存储的查询),而不需要其他的存储。

    视图如何使用

    视图提供了一种针对基表的数据进行不同的展现方式。视图是非常强大的,因为它可以针对不同的用户调整展现。视图经常用在:

    提供额外的安全性,预先限制了只能访问表的某些行或某些列

    例如图5-5显示了STAFF视图没有显示基表employees的salary或commission_pct列

    隐藏数据复杂性

    例如,一个视图可以使用join定义,从多个表中对关联的列或行进行聚集。但是,视图隐藏了这个信息是来源于多个表的事实。

    简化用户的语句

    例如,视图允许用户从多个表中查询数据却并不用知道如何执行关联(join)

    将应用程序和基表的定义隔离

    例如,如果一个视图引用了一个四列表的三列,这时候这个表增加了一个新列,然后视图定义不受影响,使用视图的应用程序不受影响。

    表示一些必须使用视图的查询

    例如,一个视图可以定义为关联一个表和一个group by 视图,或者视图可以定义为一个表和union视图

    保存复杂查询

    例如,一个查询可能对表信息进行大量的计算。通过将查询保存为视图,你可以在查询视图时每次都执行计算。

    视图的机制

    Oracle将定义视图的查询的文本保存在数据字典中。当你在SQL语句中引用视图时,Oracle:

    1、将引用视图定义的查询合并到语句中

    2、在一个SQL共享区域解析合并的语句

    3、执行语句

    只有在共享SQL区域中不包含类似的语句,Oracle会在新的共享SQL区域中执行引用视图的语句。因而当你使用视图时,你通过共享SQL(视图的SQL)可以降低内存消耗。

    视图参数支持国际化

    当Oracle评估包含国际化支持的参数(如TO_CHAR,TO_DATE和TO_NUMBER)文字字符或者SQL函数时,Oracle使用会话默认支持的国际化参数。你可以通过在视图定义中指定国际化支持的参数来覆盖默认值。

    使用针对视图的索引

    Oracle通过将视图定义的查询合并到原始查询中来确定是否使用视图针对的查询的索引。

    考虑下列视图:

    CREATE VIEW employees_view AS 

      SELECT employee_id, last_name, salary, location_id

        FROM employees JOIN departments USING (department_id)

        WHERE departments.department_id = 10; 

    现在看看下列用户发布的SQL:

    SELECT last_name 

      FROM employees_view 

      WHERE employee_id = 9876; 

    Oracle处理好的查询结构如下:

    SELECT last_name 

      FROM employees, departments

      WHERE employees.department_id = departments.department_id AND 

            departments.department_id = 10 AND

            employees.employee_id = 9876; 

    在尽可能的情况下,Oracle将视图定义的查询和任何潜在的视图定义的查询都合并起来。Oracle优化合并的查询就好像你没有引用任何视图的查询一样。因而,Oracle可以使用任何引用的基表列的索引,不管是视图定义引用的列,还是针对视图的查询都可以。

    某些情况下,Oracle不能将视图定义和用户提交的查询合并,这时候,Oracle就不能使用引用列的所有索引了。

    依赖和视图

    因为视图是一个引用其他对象(表、实体化视图或其他视图)的查询的定义,所以视图依赖它引用的对象。Oracle自动处理视图依赖。例如,如果你删除了视图的一个基表然后重新创建了它,Oracle会检查新的基表是否适合已有的视图定义。

    可更新关联视图

    关联视图指的是在视图定义的FROM字句中包含多个表或视图,而且没有使用任何子句:DISTINCT,聚集,GROUP BY,START WITH,CONNECT BY,ROWNUM和并集操作(UNION ALL,INTERSECT等等)。

    可更新关联视图是包含多个表或视图允许执行UPDATE、INSERT、DELETE操作的关联视图。数据字典视图ALL_UPDATE_COLUMNS、DBA_UPDATEABLE_COLUMNS和USER_UPDATE_COLUMNS包含的信息指明了视图的哪些列是可以更新的。为支持可更新属性,视图不能包含任何下列结构:

    并集操作符

    DISTINCT操作符

    聚集或者分析函数

    GROUP BY、ORDER BY,CONECT BY或者START WITH子句

    SELECT列表中的集合表达式

    SELECT列表的子查询

    关联(某些特殊情况)

    不可更新的视图可以使用INSTEAD OF触发器修改。

    对象视图

    在Oracle对象关系数据库中,有一种对象视图让你可以获取、更新、插入和删除关系型数据,就好像它作为一个对象类型保存一样。你还可以定视图的类型为对象数据类型,比如object、REF和聚集(嵌套表和VARRAYS)。

    内联视图

    内联视图不是模式对象。它是一个使用别名(关联名)的子查询,你可以在SQL语句中像视图一样使用它。

    实体化视图概述

    实体化视图一种用来汇总、计算、复制和分发数据的模式对象。它们很适合多种计算环境,比如数据仓库、决策支持、分布式或移动计算:

    在数据仓库中,实体化视图用来计算和保存聚集数据,比如总数和平均值。这些环境的实体化视图是典型的汇总数据,因为它们保存着汇总的数据。它们可以用来使用聚集关联或者非聚集关联。如果是Oracle 9I或更高版本,实体化视图可以支持包含过滤条件的查询。

    优化器可以自动识别实体化视图是否适合查询的需要,如果适合的话会使用实体化视图来提供查询性能。优化器透明的使用实体化视图重写请求。查询然后直接指向实体化视图,而不是指向底层的表或视图。

    在分布式环境中,实体化视图是用来在分布式站点之间复制数据和在多个站点之间同步更新的冲突解决方案。实体化视图提供了远程站点的数据在本地访问的复制品。

    在移动计算环境中,实体化视图用来从中心服务器下载数据的子集到移动客户端,还提供从服务器的定期更新,并且可以将客户端的改变传回中心服务器。

    实体化视图在一些方面和索引很像:

    它们消耗存储空间

    主表数据改变时,它们必须被刷新

    它们可以使用查询重写来提高SQL执行性能

    对于SQL应用程序和用户来说完全透明

    和索引不同的是,实体化视图可以直接使用SELECT子句访问。依赖需要的不同的刷新类型,它们可以直接使用INSERT、UPDATE、DELETE语句访问。

    在视图上定义约束

    数据仓库应用程序在Oracle数据库中通过关系模式的引用完整性约束(RI constraints)来标识维度数据。引用完整性约束代表表之间的主键和外键约束。通过查询Oracle数据字典,应用程序可以识别引用完整性约束,因而识别数据库中的多维度数据。在某些环境下,数据库管理员基于安全或模式复杂性的考虑,会在维度表和事实表上定义视图。Oracle提供了约束视图的能力。通过允许视图之间的完整性定义,数据库管理员可以将基表的约束传递到视图上,因而允许应用程序在严格限制的环境中识别多维度数据。

    视图上只能定义逻辑约束,逻辑约束只是声明而不强制的约束。这些约束的目的不是为了强制任何商业规则,而是为了标识多维度数据。下列约束可以定义在视图上:

    主键约束

    唯一约束

    引用完整性约束

    对于一个给定的视图,有效约束状态有声明(declarative)、失效(DIABLE)和无效(NOVALIDATE)。但是也允许RELY或NORELY状态,因为视图上的约束可以用来启动更精密的查询重写;一个视图约束为RELY状态会在重写完整性级别设置为trusted模式时启动查询重写。

    注意:虽然视图约束定义是在视图上定义,在视图上操作的,但是本质上从属于底层基表的约束完整性定义,视图的约束可以通过基表的约束强制执行。

    刷新实体化视图

    Oracle维护实体化视图的方式是在它们的主表修改发生之后刷新实体化视图。刷新方式可以是增量的(fast refresh)或者完全(complete)。对于使用快速刷新模式的实体化视图,实体化视图日志或者直接装载日志保存了主表的修改记录。

    实体化视图可以根据命令和一定时间间隔周期来刷新。在同一个数据库中,实体化视图可以在主表的事务提交改变的时候是实时刷新。

    实体化视图日志

    一个实体化视图是一个记录主表数据修改记录的模式对象,所以定义在主表上的数据可以增量刷新。

    每个实体化视图日志和一个主表相关联。实体化视图日志和主表位于同一个数据库同一模式下。

    维度概述

    一个维度定义多列或列集合的继承关系(父/子)。子级别的每个值和父级别有且只有一个值关联。继承关系是从继承的一个级别到继承的下一个级别的函数依赖。维度是列之间的逻辑关系的容器,而且它不需要分配任何数据存储空间。

    CREATE DIMENSION语句指定:

    多个LEVEL子句,每个代表维度中的一列或列集合

    一个或多个HIERARCHY子句代表临近级别的父子关系

    可选ATTRIBUTE子句,每个代表单独级别的关联列或列集合

    维度中的列来自于同一个表(非规泛化的)或者来自于多个表(完全或部分规泛化)。在多个表上的多个列上定义维度,使用HIERARCHY子句的JOIN子句来连接数据库。

    序列生成器概述

    序列生成器提供了一个数列的生成顺序。序列生成器在多用户环境中生成唯一顺序数字时非常有用,而不会增加磁盘I/O或事务锁的负载。例如,假设两个用户同时对employees插入新的employee行。通过使用序列来针对employee_id列生成唯一雇员号码,用户不需要等待另一个用户就可以插入下一个雇员号码。序列自动为每个用户创建正确的值。

    因此,在两个事务的语句必须同时产生序列号时,序列生成器降低了串行度。通过避免多个用户等待其他用户生成和等待序列号造成的串行化,序列生成器提高了事务吞吐量,单个用户的等待会尽可能的短。

    序列号是Oracle内部定义的长达38字节的整数。一个序列定义展现了基本信息,通常如下:

    序列名称

    序列升序还是降序

    数字之间的间隔

    Oracle是否应该在内存中缓存一系列的生成的序列号

    Oracle在数据库的SYSTEM表空间的单个数据字典的行保存所有序列的定义。因而,所有序列定义是可见的,因为SYSTEM表空间总是在线。

    SQL语句引用了序列就可以使用序列号。你可以发布一个语句来生成一个新的序列号或者使用当前序列号。在用户会话中,一个语句产生一个序列号之后,这个序列号只对这个会话可见。引用序列的每个用户都可以访问当前的序列号。

    序列号的创建和表无关。因而,相同的序列号生成器可以给多个表使用。生成序列号对你在数据上自动产生主键和在多个表或多个行产生相同的键值。如果序列号在事务中生成、使用且最后回滚了,序列号就会产生跳跃。如果想的话,应用程序可以预作安排来捕捉和重用这些序列号。

    注意:如果你的应用程序从来不丢失序列号,或者你不能使用Oracle序列,你可以选择在数据库表中保存序列号。使用数据库表实现序列生成器要非常小心。即使在单实例情况下,对于高频率的序列值生成,保存序列值的行的锁消耗可能是个性能瓶颈。

    同义词概述

    同义词是一个对象的别名,对象可以使任何表、视图、实体化视图、序列、过程、函数、包、类型、Java类模式对象、用户定义的对象类型或者其他的同义词。因为同义词只是一个别名,它只需要在数据字典中定义而不需要其他存储空间。

    同义词经常基于安全和方便原因采用。例如,它们可以达到如下目的:

    隐藏对象的名字和拥有者

    为分布式数据库的远程对象提供本地透明性

    为数据库用户简化SQL语句

    可以对精细权限控制的专用视图提供有限度的访问

    你可以创建公用和私用同义词。一个公用同义词的拥有者是叫做PUBLIC的特定用户组,数据库中的每个用户都可以访问这个同义词。私用(private)同义词在指定用户的模式下,对其他用户的访问可以进行控制。

    同义词在分布式数据库环境和非分布式数据库环境中都非常有用,因为它隐藏了底层对象的标识,还包括在分布式系统中的位置。同义词有很大的优点,因为如果底层对象被重命名或者移动了,只需要重新定义同义词就可以了。基于同义词的应用程序可以正常工作而不需要做任何修改。

    同义词可以简化分布式数据库环境中的用户的SQL语句。下面的例子显示了数据库管理员经常创建公共同义词来隐藏基表的标识和降低SQL语句复杂性的方法以及原因。假定下列情况:

    用户JWARD拥有的模式有一个叫做SALES_DATA的表

    表SALES_DATA的SELECT权限赋予了PUBLIC

    这样的话,你不得采取类似的SQL语句来查询SALES_DATA表:

    SELECT * FROM jward.sales_data;

    你可以注意到必须一起使用表名和包含表名的模式来执行查询。

    假定数据库管理员使用如下SQL语句创建一个公共同义词:

    CREATE PUBLIC SYNONYM sales FOR jward.sales_data;

    创建公共同义词之后,你可以使用一个简单的SQL语句查询表SALES_DATA:

    SELECT * FROM sales;

    可以注意到公共同义词SALES隐藏了表SALES_DATA的名称和包含它的模式的名称。

    索引概述

    索引是表和聚集表可选的关联结构。你可以在表的一个或多个列上创建索引来加快其上的SQL语句执行速度。就如同使用本手册的索引比没有索引可以帮你快速定位信息一样,一个Oracle索引提供了对于表数据更快的访问方法。正常情况下,索引是降低磁盘I/O的主要方法。

    你可以在表上创建很多索引,可以使用列的任意不同组合来创建索引。你可以在相同的行上创建多个索引,只要列的组合顺序不同就可以了。例如,下列语句指定了有效的组合:

    CREATE INDEX employees_idx1 ON employees (last_name, job_id); 

    CREATE INDEX employees_idx2 ON employees (job_id, last_name); 

    Oracle提供了多个索引模式,提供了针对不同情况下的性能优化:

    B树索引

    B树聚集索引

    Hash聚集索引

    反向键值索引

    位图索引

    位图联结索引

    Oracle还支持函数索引和指定应用程序或使用范围的域索引。

    增加或者减少索引并不需要修改任何的SQL语句的语法。索引只是数据的快速访问途径。它只影响执行速度。假定一个数据被索引,索引就会直接指向包含这个值的行的位置。

    索引在逻辑上和物理上都和关联表的数据独立。你可以任何时候创建和删除索引而不会影响基表以及其他的索引。如果你删除索引,所有的应用程序可以继续运行。但是,以前访问删除的索引的数据会降低速度。索引是一个独立的结构,还是需要存储空间的。

    索引创建后Oracle自动维护和使用索引。不需要用户额外操作,Oracle会自动将数据改变(比如增加行、修改行或删除行)反映到相关索引上。

    索引数据的获取性能基本保持一致,甚至增加了新行也是如此。但是一个表上存在多个索引还是会降低更新、删除和插入的性能,因为Oracle必须更新表的相关索引。

    优化器可以使用现存的索引来构建另一个索引。这样会创建一个更快的索引。

    唯一和非唯一索引

    索引可以是唯一或者非唯一的。唯一索引保证表在索引列(一个或多个)没有重复的行值。非唯一索引并不强迫限制列值(唯一)。

    Oracle推荐显示的使用CREATE UNIQUE INDEX语句来创建唯一索引。通过主键或唯一约束来创建唯一索引并不一定会创建新索引,而且创建的索引也不确保是唯一索引。

    复合索引

    复合索引(也叫关联索引)是一个在一个表的多个列上创建的索引。复合索引的列可以是任何顺序的,并且不需要在表中相邻。

    在SELECT语句的WHERE子句引用了复合索引的全部或者起始列的情况下,复合索引可以加快获取数据的速度。因而,定义中使用的列的顺序非常重要。通常,最常访问或最高选择率的行放在前面。

    图5-6说明了VENDOR_PARTS表在VENDOR_ID和PART_NO列上有一个复合索引。

    图 5-6 符合索引示例

    通常一个复合索引不能超过32个列。对于位图索引来说,列数最大数目为30。一个键值大致不能超过一个数据块的可用空间的一半(多个限制的最小值)。

    索引和键

    虽然这个两个概念经常可以互换,但索引和键还是有区别的。索引是保存在数据库中的物理存储的结构,用户可以使用SQL语句创建、修改和删除索引。创建索引是为了提供一种的更快的访问表数据的方式。键严格来说是一种逻辑概念。键对应于Oracle叫做完整性约束的这个特性,这个约束在数据库中强制了商业规则。

    因为Oracle使用索引来强制一些完整性约束,键和索引经常互换的使用。但是,不要对它们彼此产生混淆。

    索引和NULL

    索引中的NULL值一般认为是不同的,除非索引中的2个或者更多的非NULL值行是一样的,这种情况下,这些行被认为是相等的。因而UNIQUE索引不允许重复值,所以索引不包含NULL值(即NULl值不索引)。如果整个行全为空,索引不会起作用。

    Oracle不对所有键值为NULL的列索引,除非是在位图索引或聚集键列值为NULL的情况下。

    函数索引

    你可以针对包含表中一个或多个列的函数和表达式建立索引。一个函数索引计算函数或表达式的值并保存在索引中。你可以创建B树函数索引,也可以创建位图函数索引。

    构建索引的函数可以是数学表达式,也可以包含PL/SQL函数、包函数、C标注、SQL函数。表达式不能包含任何聚集函数,并且必须是有确定值的。对在需要构建索引的行包含的对象类型,函数可以是该类型的一个方法,比如映射方法。但是,你不能在LOB、REF或嵌套表列构建函数索引,而且如果对象类型包含LOB、REF或嵌套表的话,也不能构建函数索引。

    函数索引的使用

    函数索引为评估WHERE子句包含函数的语句提供了一个高效机制。表达式值是计算和保存在索引中的。当你执行INSERT和UPDATE语句时,Oracle也必须计算这个函数来执行这个语句。

    例如,如果你创建下列索引:

    CREATE  INDEX  idx  ON  table_1 (a+b*(c-1),a,b);

    然后Oracle在处理下列查询时可以使用它:

    SELECT  a  FROM  table_1  WHERE  a+b*(c-1)<100;

    UPPER(column_name)或者LOWER(column_name)定义的函数索引可以加快大小写不敏感的查询速度。例如,下列索引:

    CREATE  INDEX  uppercase_idx  ON  employees  (UPPER(first_name));

    可以在处理下列查询时使用:

    SELECT * FROM employees WHERE UPPER(first_name) = 'RICHARD'; 

    基于函数索引可以提供国际化支持的排序索引,这样可以在SQL语句中提供高效的多语言校订。

    函数索引的优化

    你必须对优化器收集函数索引的统计信息。否则索引无法用来执行SQL语句。

    优化器可以对WHERE子句的表达式使用函数索引的索引范围扫描。例如,在这个查询中:

    SELECT * FROM t WHERE a + b < 10; 

    如果构建了a+b这样的索引,优化器可以执行索引范围扫描。索引扫描路径在断语(WHERE子句)有低选择率时非常有用。另外,如果表达式在函数索引中实现了,优化器可以更准确的评估短语包含的表达式的选择率。

    优化器通过解析SQL语句来执行表达式匹配,然后比较语句的表达式树和函数索引。比较是不分大小写和忽略空格的。

    函数索引的依赖

    函数索引依赖于定义索引的表达式使用的函数。如果函数是PL/SQL函数或者包函数,函数定义的任何改变都会将索引失效。

    创建一个函数索引,用户必须有CREATE INDEX或CREATE ANY INDEX权限。

    想要使用一个函数索引:

    索引创建之后表必须分析过

    查询必须确保索引表达式不包含任何NULL值,因为NULL值没有保存在索引中。

    下面部分描述了额外的需求。

    函数确定性

    任何用户自定义的函数想使用到函数索引必须采用DETERMINISTIC关键字来声明,指出函数无论何时对于任何给定的输入参数值,函数会产生相同的输出。

    定义函数的权限

    索引拥有者需要函数的EXECUTE权限才能在函数索引上使用这个函数。如果EXECUTE权限被撤销,Oracle将索引标识为无效(DISABLE)。索引拥有者不需要函数的EXECUTE WITH GRANT OPTION权限来分配基表的SELECT权限。

    解决函数索引的依赖关系

    函数索引依赖于任何它使用的函数。如果函数或包含这个函数的包重新定义了(或者如果索引拥有者的EXECUTE权限被取消),然后会发生下列情况:

    索引被标记为无效(DISABLE)

    如果优化器选择使用的索引被标记无效,当前涉及这个查询的查询会失败

    标记为DISABLE的索引上的DML操作也会失败,除非索引是标记为UNUSABLE和初始化参数SKIP_UNUSABLE_INDEXES标记为真(true)。

    函数修改之后想要重新生效索引,可以使用ALTER INDEX ... ENABLE语句。

    索引如何存储

    当你创建一个索引时,Oracle在表空间上自动分配一个索引段来保存索引数据。你可以使用下列方式控制索引段的空间分配和备用空间的使用:

    设置索引段的存储参数来控制索引段的区段的分配

    设置索引段的PCTFREE参数来控制组成索引段的区段的数据块的空闲空间

    索引段的表空间可以是拥有者的默认表空间或者CREATE INDEX语句指定名字的表空间。你不必将索引放在和关联表相同的表空间中。此外,你可以通过将索引和表放在位于不同磁盘驱动器的不同表空间上可以提高使用索引的查询速度,因为Oracle可以并发的获取索引和表的数据。

    索引块的格式

    索引数据的可用空间是Oracle块大小减去块首部、条目首部、rowid、和每个索引值的一个长度字节。

    当你创建索引时,Oracle将索引列取出和排序,并把每一行的索引值和rowid一起保存。然后Oracle从下往上装载索引。例如,考虑如下语句:

    CREATE INDEX employees_last_name ON employees(last_name); 

    Oracle将employees表根据last_name排序。然后按照排序顺序来装载last_name和对应的rowid值到索引上。当它使用这个索引时,Oracle对排序的last_name值快速扫描,然后使用查询到的last_name值关联的rowid值来定位行。

    索引的内部结构

    Oracle使用B树索引来加快数据访问。没有索引的情况下,你不得不依次扫描数据来找到值。对于n行来说,平均的查询行数为n/2。这个不会随着数据量的增加而缩放。

    考虑将一个值的排序列表分成多个块宽度的范围(页块)上。块的末尾除了块的指针之外都可以保存在一个搜索树中,n条数据花费log(n)的时间就可以找到。这就是Oracle索引隐含的基本原理。

    图5-7 B树索引的内部结构

    B树索引的较高的块(树枝块)包含指向低级别索引块的索引数据。最低级别的索引块(叶块)包含每个索引数据和用来定位实际行的对应的rowid。页块是双向关联的。索引列的包含的字符集数据是基于数据库的字符集的二进制字符。

    对于唯一索引,每个数据值对应一个rowid。对于非唯一索引,排序序列中包含rowid,所以非唯一索引通过索引键和rowid排序。包含null的所有键值不索引,除非是聚集索引。两行都包含null,不违反唯一约束(因为Null是互不相同的)。

    索引属性

    有两种类型的块:

    搜索使用的树枝块

    页块保存的值

    树枝块

    树枝块保存下列内容:

    两个键之间需要用来分叉的最小键前缀

    指向包含键值的子块

    如果块拥有n个键,,那么它们包含n+1个指针。键和指针的数量由块大小限制。

    页块

    所有的页块到根块的高度都相同。页块保留下列信息:

    每行的全部键值

    表行的ROWID

    所有的键和ROWID对都是左右相连的。他们按照(key,ROWID)排序。

    B树结构的优势

    B树结构有如下优势:

    树的所有页块高度相同,所以获取索引上任何地方的任何数据所需的时间大致相同

    B树索引自动保持均衡状态

    B树索引的所有块平均来说是3/4满的

    B树对大多数查询提供了优秀的检索性能,包括精确识别和范围搜索

    插入、更新和删除都是高效的,并维护键顺序以便快速的获取数据

    B树索引对于小表和大表同样优秀,并且不会随着表尺寸的增长而降低性能

    索引唯一扫描

    索引唯一扫描是最高效的访问数据方式之一。这个访问方式用来从B树索引返回数据。在B树唯一索引的所有行指定相等条件时,优化器会选择索引唯一扫描。

    索引范围扫描

    索引范围扫描是访问选择性数据的通常操作。它可以是有限制的(两边都有界限)或者无限制的(在一边或者两边)。数据按照索引列的升序返回数据。值相同的多个行按照ROWID升序保存。

    键压缩

    键压缩使你可以压缩索引或索引组织表的主键列值的一部分,这样可以减少重复数据造成的存储瓶颈。

    通常,索引中键分为两类,一类是分组键,一类是唯一键。如果键没有定义为唯一键,Oracle将rowid加到分组键中。键压缩是一种减少分组键,并保存它的方法,这样可以由多个唯一键共享。

    条目的前缀和后缀

    键压缩将索引键分为前缀条目(分组部分)和后缀条目(唯一部分)。压缩通过在索引块的后缀条目之间共享前缀条目来获得。只有B树索引的叶块能够压缩。枝块的键后缀可以被截断,但是键不能被压缩。

    键压缩发生在一个索引块内,不会跨多个索引块。后缀条目组成了索引行的压缩版本。每个后缀条目引用一个前缀条目,它和后缀条目保存同一个索引块中。

    默认情况下,由所有键值列组成的前缀不包括最后一个。例如,在一个由三个列(column1,column2,column3)组成的键中,默认的前缀是(column1,column2)。对于一系列值(1,2,3), (1,2,4), (1,2,7), (1,3,5), (1,3,4), (1,4,4),重复出现的(1,3),(1,2)前缀被压缩。

    作为可选方案的是,你可以指定索引长度,索引长度是前缀列的数目。如果指定了前缀长度为1,然后前缀是column1,后缀是(column2,column3)。对于下列值(1,2,3), (1,2,4), (1,2,7), (1,3,5), (1,3,4), (1,4,4),前缀中重复发生的1被压缩。

    非唯一索引的最大前缀长度是键值列的数目,唯一索引的最大前缀长度是键值列的数目减1。

    只有在索引块中不包含相等的前缀条目才会将前缀条目写入索引块。前缀条目在写入之后就立刻可以共享,并且保持到最后删除的引用后缀条目被清理出索引块为止。

    性能和存储考虑

    键要所会节省大量的空间,让你可以在每个索引块上保存更多的键,这样会导致更少的I/O和更好的性能。

    虽然键压缩减少了索引需要的存储空间,它却提高了在索引扫描时重构键值时需要的CPU时间。它还会导致额外的空间消耗,因为每个前缀条目对应有4个字节的消耗。

    键压缩的使用

    键压缩在某些情况下非常有用,如:

    在通常的非唯一索引中,Oracle将rowid加到键上来确保唯一行。如果使用键压缩,Oracle将除rowid的重复键作为前缀条目保存在索引块中。剩下的后缀条目只由rowid组成。

    同样的情况可以在键值组成为(item,time,stamp)的唯一索引中哦个看到。例如(stock_ticker, transaction_time)。上千行可能拥有相同的stock_ticker值,通过transaction_time保持唯一。在特定的索引块,一个stock_ticker值只作为前缀条目保存一次。索引中其他的条目是transaction_time值,可以作为后缀条目保存,引用通用的stock_ticker前缀条目就可以了。

    在包含数据类型为VARRAY或者NESTED_TABLE的索引组织表中,对象标识符对于每个聚集数据类型都是重复的。键压缩是你可以压缩重复的对象标识符。

    在某些情况下,键压缩无法使用。例如,在只包含一个属性键的唯一索引,键压缩就不可能,因为只有唯一的部分,不存在分组的部分来共享。

    反向键索引

    和标准索引不同,创建一个反向键索引在保持列顺序的同时反转索引列(除rowid之外)的字节顺序。这样处理可以避免RAC环境中修改的索引集中在页块的一小部分上造成的性能降低。通过反转索引的键值,插入会在索引中分布跨越所有的叶。

    使用反转键方法会降低在索引上运行索引范围扫描查询的能力。因为词典临近的键值在反转键索引中并没有保存在一起,只有按键值取数据或者全索引(表)扫描能够执行。

    有时候,使用反转键索引能够使得OLTP真正应用集群(RAC)运行的更快。例如,在一个e-mail应用程序中保持邮件信息的索引:某些用户保留旧消息,索引必须象最近的消息一样维护指向这些消息的指针。

    REVERSE关键字提供了一种创建反向键索引的简单机制。你可以在CREATE INDEX语句中可选的索引定义中指定REVERSE关键字。:

    CREATE INDEX i ON t (a,b,c) REVERSE; 

    你可以指定关键字NOREVERSE来将一个反转键索引重建为非反转键索引:

    ALTER INDEX i REBUILD NOREVERSE; 

    不使用NOREVERSE关键字重建一个反转键索引会重建一个反转键索引。

    位图索引

    索引的目的是为表中包含一个给定键值的行提供一个访问指针。在通常的索引中,通过针对每个键保存包含这个键值的行的rowid达到这种效果。Oracle针对每个rowid重复的保存键值。对于位图索引来说,每个键值使用一个位图,在通常索引中,每个键值对应一系列的rowid。

    位图的每个位对应一个潜在的rowid。如果设置了位,就意味着对应rowid的行包含这个键值。位图索引虽然采用了不同的内部表现,但是通过一个映射函数将位转换为实际的rowid,这样位图索引提供了通常索引同样的功能。如果不同的键值数量很少,那么位图索引是非常节省空间的。

    位图索引针对WHERE子句的多个条件的索引进行高效的合并。符合条件的某些而不是全部的行在访问表之前就被过滤掉了。这常常戏剧化的提高了反应时间。

    数据仓库应用程序的受益

    位图索引对数据仓库应用程序很有用处,数据仓库拥有大量的数据和特殊的查询,但是只有很低数量级的并发事务。对这样的应用程序,位图索引提供:

    降低对于大量特定查询的反应时间

    对于其他索引技术可以大量节省空间

    在非常低端的硬件上也能获得令人惊异的性能

    并发的DML和装载数据非常高效

    对于一个大表使用传统的B树索引来全部索引对于空间来说是非常昂贵的,因为索引可能比表中的数据大好几倍。位图索引只占表中被索引数据的一小部分。

    位图索引对于包含大量并发修改数据的事务的OLTP应用程序并不适合。这些索引适合数据仓库应用程序的决策支持,这类系统通常查询数据而不是更新数据。

    位图索引对于索引列主要是比较大小的情况也不适合。例如,一个经常出现在WHERE子句来对于特定值比较大小的salary列在B树索引下性能更好。位图索引只对相等查询比较有用,尤其是AND、OR、NOT操作符的组合。

    Oracle优化器和执行引擎集成了位图索引。其他的Oracle执行方法也与位图索引无缝集成。例如,优化器可以在使用位图索引的表和通常的B树索引的表上执行hash连接。优化器考虑位图索引和其他可用的访问方式(比如通常的B树索引和全表扫描),选择最高效的方式,在适当的时候一起考虑这些方式。

    并发查询和并发的DML对于位图索引和传统索引来说是差不多的。分区表中的位图索引必须是本地索引。也支持并行创建索引和创建关联索引。

    基数

    使用位图索引对于低基数列非常有优势:低基数行就是哪些不同值的数量和表行数比非常小。如果列的不同值的数量少于表行数的1%,或者列值重复100次以上,那么这个列就是位图索引的候选者。即使一列重复次数不多,只要高基数列经常在WHERE子句中包含复杂的条件查询也可以。

    例如,一个拥有100万的行,1万个不同值的列适合做位图索引。这列的位图索引比B树索引要好,尤其是这列经常和其他列关联查询时。

    B树索引对于高基数列非常高效:就是说拥有很多可能的值的列,例如CUSTOMER_NAME或PHONE_NUMBER。在某些情况下,B树索引可能远远大于索引数据。适当使用的话,位图索引比比对应的B树索引小很多。

    在特定查询和类似的条件下,位图索引可以戏剧化的提高查询性能。一个查询中的WHERE子句中的AND和OR条件可以在转换位图结果到rowid之前在位图上直接执行对应的布尔操作来快速获得。如果目标行数较小,查询可以很快返回,而不需要对于全表扫描结果重新排序。

    位图索引例子

    表5-1显示了一个公司顾客数据的一部分。

    表5-1位图索引的例子

    CUSTOMER #

    MARITAL_ STATUS

    REGION

    GENDER

    INCOME_ LEVEL

    101

    single

    east

    male

    bracket_1

    102

    married

    central

    female

    bracket_4

    103

    married

    west

    female

    bracket_2

    104

    divorced

    west

    male

    bracket_4

    105

    single

    central

    female

    bracket_2

    106

    married

    central

    female

    bracket_3

    MARITAL_STATUS,REGION,GENDER和INCOME_LEVEL都是低基数列。婚姻状况(marital status)和地域(region)只有3个可能值,性别(gender)只有2个可能值,收入水平(income level)有4个可能值。因为,这些行适合创建位图索引。一个位图索引不应该创建在CUSTOMER#上,因为这个是高选择性列。相反,在这个列上使用唯一B树索引可以提供更高效的展现和获取效率。

    表5-2描述了例子中的REGION列的位图索引。它有三个独立的位图组成,每个针对一个区域

    图5-2 位图例子

    REGION='east'

    REGION='central'

    REGION='west'

    1

    0

    0

    0

    1

    0

    0

    0

    1

    0

    0

    1

    0

    1

    0

    0

    1

    0

    位图中的每个条目或位都对应CUSTOMER表的一行。每个位的值对应表中对应行的值。例如,在位图REGION='east'第一位是1。因为CUSTOMER表的第一行的region是east。位图REGION='east'其他位都是0,因为这个表的其他REGION列都不包含east行。

    任何关于公司客户的人口统计学分析调查都会问:“住在中部或西部区域的已婚顾客有多少?”这对应下列的SQL查询:

    SELECT COUNT(*) FROM CUSTOMER  

        WHERE MARITAL_STATUS = 'married' AND REGION IN ('central','west'); 

    位图索引可以高效的处理在位图结果中计算数目的查询,图5-8显示了这个情况。为了标识出哪些指定的客户满足条件,位图结果可以用来访问表。

    图5-8 使用位图索引运行查询

    位图索引和空值

    和大多数其他类型的索引不一样,位图索引可以包含NULL值的行。对NULL索引对有些类型的SQL语句非常有用,例如聚集函数COUNT的查询。

    分区表的位图索引

    和其他索引一样,你可以在分区表上创建位图索引。唯一的限制是位图索引必须是分区表的本地索引,不能是全局索引。只有非分区表才支持全局位图索引。

    位图关联索引

    除了单个表的位图索引之外,你可以创建位图关联索引,这是一个关联两个或者更多表的位图索引。一个位图关联索引可以显著的减少那些必须通过限制条件关联的数据的容量。对于表中每个列的每个值,位图索引保存了一个或多个表的行的rowid。在数据仓库环境中,关联条件是主键列或者维度表列或者事实表的外键列的内部相等关联。

    位图关联索引比实体化关联视图在存储上更有效率,是更好的实体化关联视图的替代方法。这是因为实体化关联视图不能压缩事实表的rowid。

    索引组织表概述

    索引组织表的存储组织是主键B树索引的变体。通常的表(堆组织表)的数据在无顺序的聚集(堆)中保存,索引组织表的数据保存在主键排序的B树索引结构中。除了在索引组织表的行中保存主键列的值之外,B树的每个索引条目保存了非键值列的值。

    在图5-9所示,索引组织表索某种程度上类似于一个通常表和一个在一个或者多个表列上的索引组成的结构,但是不是维护两个单独的存储结构(一个表、一个B树索引),数据库管理员只维护一个单独的B树索引。而且,和索引条目只包含行rowid不同,非键列值也会保存。因而,每个B树索引包含 <primary_key_value, non_primary_key_column_values>.

    图5-9 通常表和索引组织表的结构比较

    应用程序使用SQL语句处理索引组织表,和通常的表处理方法没什么区别。但是,数据库系统通过操作对应的B树索引来执行所有的操作。

    表5-3汇总了索引组织表和通常表的不同之处。

    表5-3 比较索引组织表和通常表

    通常表

    索引组织表

    Rowid唯一标识一行,主键是可选的

    主键唯一标识一行。主键是必须的

    伪列ROWID的物理ID允许构建辅助索引

    伪列ROWID的逻辑rowid允许构建辅助索引

    通过物理rowid访问

    通过逻辑rowid访问

    顺序扫描返回所有行

    全索引扫描返回所有行

    可以和其他表保存在聚集中

    不能保存在聚集中

    可以包含一个类型为LONG的列和多个LOB类型的列

    可以包含LOB列,但不能包含LONG列

    索引组织表的优势

    索引组织表加快了根据主键或者主键的任何有效前缀查找表行的速度。包含行的B树页块中保存了一个行的非键列,所以避免了额外的块访问。而且,因为行是按照主键顺序保存的,主键或有效前缀的范围扫描只需要最少的块访问。

    为更快的访问经常访问的列,你可以使用行溢出段(后面会提到)来将不常访问的非键列从B树索引的页块移到可选的溢出段(堆组织)。这就限制了行在B树索引页块中保存的大小和条目部分,这会产生一个更小的B树和每个页块保存更高数目的行。

    拥有主键索引的堆组织表的主键同时保存在表和索引上,索引组织表只在B树索引中保存主键列,而不是重复保存。

    因为行是按照主键顺序保存的,所以通过键压缩可以节省额外的存储空间。

    基于逻辑rowid(和物理rowid相对应)的主键在索引组织表的辅助索引中效率很高。这是因为对于逻辑的rowid,即使在表重新组织导致表行移动也不会导致辅助索引不可用。同时,通过逻辑rowid来猜测物理rowid,基于索引组织表的辅助索引的访问性能可以和直接访问通常表的辅助索引性能相提并论。

    使用行溢出段的索引组织表

    B树索引的条目通常很小,因为它们只包含键值和rowid。但在索引组织表中,B树索引条目可能很大,因为它们由整个行组成。这可能会破坏B树索引的密集聚集特性。

    Oracle提供了OVERFLOW子句来处理这个问题。所以你可以指定一个溢出表空间,如果需要的话,一行可以可以分成两个部分:一部分保存在索引中,一部分在溢出存储区域段。

    索引条目,包含所有的主键列的列值和一个指向行溢出的的物理rowid指针以及可选的一部分非键列。

    溢出部分,包括剩余的非键列的列值。

    和OVERFLOW一起,你可以使用两个子句PCTTHRASHOLD和INCLUDING来控制Oracle如果确定一行是否保存为两个部分,还包括在行中的哪些非键列分开。使用OCTHRESHOLD,你可以指定一个块大小的百分比的阀值。如果所有的非键列值适合指定大小的限制,行就不会分成两部分。否则,从不能容纳的第一个非键列开始,剩下的非键值列都保存在表的行溢出段中。

    INCLUDING子句可以让你指定一个列名,这样在CREATE TABLE语句中在指定列的后面的非键列都保存在溢出段上。不过需要注意的是,由于PCTTHRESHOLD基线的限制,额外的非键列有时候需要保存在溢出段中。

    索引组织表的辅助索引

    索引组织表的辅助索引提供了对非主键或者非主键的前缀的列访问的高效方式。

    Oracle在索引组织表上使用基于表主键的逻辑行标识(逻辑rowid)构建辅助索引。逻辑rowid包含一个物理猜测,这个标识了行的块位置。Oracle可以使用这些物理猜测来直接探测索引组织表的页块,不需要使用主键搜索。因为索引组织表中的行没有持久的物理地址,行可能会移到新的块中,所以物理猜测可能变的陈旧。

    对通常表来说,通过辅助索引访问包含辅助索引的一个扫描加上一个取得包含行的数据块的I/O。对于索引组织表来说,访问辅助索引稍有变化,依赖于是否使用物理猜测以及其准确性:

    不使用物理猜测,访问包含两个索引扫描:辅助索引扫描跟着一个主键索引扫描

    使用精确物理猜测,访问包括一个辅助索引扫描和获取包含行的数据块的额外I/O

    使用不精确的物理猜测,访问包含一个辅助索引扫描和一个取得错误数据块的I/O(通过物理猜测指明的),还有一个主键索引的扫描。

    索引组织表的位图索引

    Oracle支持分区和非分区的索引组织表上的位图索引。在索引组织表上创建位图索引表需要一个映射表。

    映射表

    映射表是一个堆组织表,包含索引组织表的逻辑rowid。明确一点就是每个映射表行包含对应索引组织表的行的逻辑rowid。因而,映射表提供了索引组织表行的逻辑rowid和映射表行的物理rowid的一一对应。

    在索引组织表上的位图索引和在堆表上的位图索引类似,但是索引组织表的位图索引使用的rowid是这些对应于基表的映射表。每个索引组织表有一个映射表,索引组织表上的所有位图索引都使用这个映射表。

    在索引组织表和堆组织表中,位图索引都可以使用一个搜索关键字访问。如果找到这个关键字,位图条目就被转化为一个物理rowid。在对组织表的情况下,这个物理rowid就用来访问基表。但是,在索引组织表的情况下,物理rowid用来访问映射表。访问映射表得到一个逻辑rowid。这个逻辑rowid用来访问索引组织表。

    虽然索引组织表的位图索引不保存逻辑rowid,但它实际上是逻辑的。

    分区的索引组织表

    你可以在索引组织表中在列值上使用RANGE、HASH、LIST来分区。分区列是组成主键列的子集。和通常的表一样,本地分区(前缀或非前缀)索引和全局分区(前缀)索引都支持分区索引组织表。

    堆组织表和索引组织表的UROWID列的B树索引

    UROWID数据类型的列可以保存基于主键的逻辑rowid来标识索引组织表的行。Oracle支持对堆组织表和索引组织表的UROWID类型列进行索引。索引支持在UROWID列的相等比较。但是索引不支持UROWID类型列的不等比较或排序。

    索引组织表应用

    索引组织表有很多优势:针对主键查询的高性能、高可用概念、减少存储空间,索引索引组织表对下列应用很理想:

    在线事务处理(OLTP)

    Internet(例如,搜索引擎和门户)

    电子商务(例如,电子商店和目录)

    数据仓库

    分析功能

    应用程序域索引概述

    Oracle提供了扩展索引来使用在特定的数据类型(如文档、空间数据、图像、视频)上构建索引和使用专业的索引技术。通过扩展索引,你可以总结特定应用程序的索引管理大纲来作为一个indextype(索引类型)模式对象和在表列或对象类型的属性上定义一个域索引(一个特定应用的索引)。扩展索引还对特定应用操作符提供高效的处理。

    Cartridge这个应用软件负责控制域索引的结构和目录。Oracle数据库服务器和应用程序交互来创建、维护和搜索域索引。索引结构本身可以保存在数据库中作为索引组织表或者作为外部文件。

    聚集概述

    聚集是一种可选的保存表数据的方法。聚集是一组共享数据块的表,这些表共享公用的行并经常一起使用。例如,employees和departments表共享了department_id列。当你聚集employees和departments表时,Oracle物理上将employees和departments表的共用department的所有行保存在相同的数据块上。

    图5-10显示了你聚集employees和departments表会发生什么:

    图5-10 聚集数据表

    因为聚集在相同的数据块上保存不同表的关系行,通常使用聚集可以提供下列好处:

    减少了聚集表关联的磁盘I/O

    改善了聚集表关联的访问时间

    在聚集表中,聚集键值是针对特定行的聚集键列的值。不管不同的表包含多少个这个聚集键值,每个聚集键值在聚集和聚集索引中只保存一次。因而,在聚集表中保存关系表和索引数据比非聚集表格式表需要的空间更少。例如,在图5-10中,可以注意到在employees和departments表中都包含相同的聚集键的值的行只保存聚集键一次。

    哈希聚集概述

    Hash聚集和普通的索引聚集表分组表数据的方式类似(聚集键的索引不是hash函数)。但是聚集索引中保存的行是基于行聚集键值的hash函数。所有包含相同键值的行在磁盘上保存在一起。

    Hash聚集在表经常使用相等查询(例如,返回dempartment 10的所有行)的情况下比使用索引表或者索引聚集好一些。对这样的查询,指定的聚集键值是hash的。Hash键值结果直接指向磁盘上保存这一行的区域。

    哈希是一种可选的保存表数据来改善数据获取性能的方法。使用哈希的办法,就是创建一个hash聚集,装载数据到聚集中就可以了。Oracle物理上在哈希聚集中保存表行,根据hash函数的结果获取数据。

    排序哈希聚集允许应用更快的获取数据,这些数据在它们插入的时候就已经排序了。

    Oracle使用一个hash函数来产生的分布数字值叫做hash值,这些值基于特定的聚集键值。哈希聚集的键和索引聚集的键一样可以是单列或者多列(多列集)。为在哈希聚集中找到或保存数据,Oracle对行聚集键值应用hash函数。哈希值结果对应于聚集中的数据块,然后Oracle可以根据发布的语句来读写它们。

    哈希聚集是使用索引的非聚集表和索引聚集的替代方案。通过索引表或索引聚集,Oracle使用保存在独立索引上的键值定位表中的行。为找到或保存索引表或聚集表的行,至少要执行两个I/O:

    在索引中找到或保存键需要一个或多个I/O

    表或聚集中行的读写的另一个I/O

    展开全文
  • Oracle 概念(Oracle 10.2)6、模式对象的依赖某些对象的定义引用了其他对象,比如视图和过程引用了表。因此,对象依赖于他们定义使用的对象。这一章描述了模式对象的依赖,以及Oracle如何自动跟踪和管理这种依赖...
  • 描述如何在asp中使用Error对象以及使用自定义的错误页面。概要 本分步指南演示如何使用新的 ASPError 对象创建自定义的、集中的错误处理页。 例如,当发生错误并且系统中的某个进程尚未完成时,应用程序可能要求向...
  • java面向对象

    万次阅读 多人点赞 2018-08-21 16:51:59
    包括面向对象概念、类与对象的关系、封装、构造函数、this关键字、static关键字、单例设计模式、继承、多态、内部类、异常、包等java基础知识。 1、面向对象 面向对象是相对面向过程而言 面向对象和面向过程都是...
  • 关于数据库的基本概念性问题

    千次阅读 2011-05-13 16:22:00
    关于数据库的基本概念性问题
  • 1.关于Java源代码文件,下列说法错误的是? A.一个源文件最多只能包含一个顶层的public类定义 B.一个源文件可以不包含任何代码定义。即它是一个空文件,编译时不会产生编译错误,一个包含类定义的最小源文件内容仅为...
  • 面向对象测试题

    2019-09-30 11:42:09
    1.下列不属于面向对象编程的特性的是(C )。 A.封装 B.继承 C.抽象 D.多态 2.(*)下述概念中不属于面向对象的是(D)。 A.对象 B.继承、多态 C.类、封装 D.过程调用 ...
  •  (2分)重载函数中不允许使用默认参数重载函数中编译根据参数表进行选择不要使用重载函数来描述毫无相干的函数构造函数重载将会给初始化带来多种方式2-3在下面类声明中,关于生成对象不正确的是( )。class point{ ...
  • Java实现面向对象编程

    万次阅读 2018-07-17 16:18:06
    目录 第1章... 10 抽象和封装...... 1.1用面向对象设计电子宠物系统......1.1.1为什么使用面向对象......1.1.2使用面向对象进行设计......1.2通过创建对象实现...1.2.3常见错误... 28 1.3使用封装优化电子宠物系统的类... ...
  • 面向对象编程思想

    万次阅读 2014-06-24 21:18:46
    面向对象是一种新兴的程序设计方法,或者说它是一种新的程序设计范型,其基本思想是使用对象,类,继承,封装,消息等基本概念来进行程序设计。 它是从现实世界中客观存在的事物(即对象)出发来构造软件系统,并...
  • 汇编语言基本概念汇总

    千次阅读 多人点赞 2015-07-28 00:14:58
    地址码字段:描述该指令的操作对象。 一般地址码字段一般是直接给出操作数;或者给出操作数存放的寄存器编号;或者给出操作数存放的存储单元的地址或有关的地址的信息。 根据地址码字段所给出的地址的个数,指令格式...
  • 面对对象测试论文

    千次阅读 2018-12-24 18:51:30
    面向对象测试技术分析 张琨1 (南昌航空大学软件学院 江西 南昌 330000) 摘 要 如今, 面向对象软件测试是计算机编程开发领域中的重要方面, 对整个行业发展有着重要的促进作用。具体而言, 在软件开发过程中, ...
  • 面向对象设计原则

    千次阅读 2014-04-09 18:10:06
    和设计模式相关的是设计原则。...面向对象设计模式描述了面向对象设计过程中、特定场景下、类与相互通信的对象之间常见的组织关系,包括它们的角色、职责、协作方式几个方面。  从编程语言来看,各种面向对象
  • 1.以下方法错误的是(A D) A 覆盖方法包括成员方法的覆盖和成员变量的覆盖 B 成员方法的覆盖是多态的一种表现形式 C 子类可以调用父类中被覆盖的方法 D 任何方法都可以被覆盖 分析:在子类中调用父类方法使用...
  • 一、 名词解释引用内联函数重载函数【问题解答】所谓引用就是给对象取一个别名,使用该别名可以 存取该对象。换句话说是使新对象和原对象共用一 个地址。内联函数是使用 inline 关键字声明的函数。 重载函数指在同一...
  • C++中类与对象的讲解(通俗易懂)

    万次阅读 多人点赞 2016-07-14 20:09:45
    概念 描述 类成员函数 类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。 类访问修饰符 类成员可以被定义为 public、private 或 protected。默认情况下是定义为 ...
  • Java 面向对象知识测试

    千次阅读 2019-12-30 16:58:40
    下面描述函数重写错误的是 A. 要有子类继承或实现 B. 子类方法的权限必须大于等于父类的权限 ...下面关于类的设计思路描述错误的是 ( ) A. 根据需求定义类所包含的字段(成员变量) B. 根据面向对象的思...
  • 目录 第 4 章 Java面向对象程序设计 一.... 二.... 三....四....五....一....1.以下关于继承的叙述正确的是( )。...A....B....2.下列不属于面向对象编程的三个特征的是 A.封装 B.指针操作 C.多态性 D.继承 3....
  • 01 C++类&对象 类定义是以关键字 class开头,后跟类的名称。 它定义了类的对象包括了什么,以及可以在这个对象上执行...概念 类成员函数 类访问修饰符 构造函数&析构函数 C++拷贝构造函数 C++友元函数 C+...
  • 非形式逻辑(01)概念及其种类

    千次阅读 2020-06-27 18:17:04
    单独概念:外延只有一个对象概念,即指称某一类特定对象概念; 普遍概念:外延由两个或两个以上对象概念。 根据概念所反映的是集合体的整体属性还是个体的特有属性,概念可以分为集合概念和 非集合概念。所谓...
  • 面向对象编程

    千次阅读 2016-12-22 15:49:58
    补充:关于 equals 和 hashCode 方法,很多 Java 程序都知道,但很多人也就是仅仅知道而已,在 Joshua Bloch 的大作《Effective Java》(很多软件公司,《Effective Java》、《Java 编程思想》以及《重构:改善既有...
  • 面向对象软件工程知识点

    千次阅读 2016-07-11 11:46:28
    面向对象软件工程知识点  1.封装是指把对象的(A)结合在一起,组成一个独立的对象。 A.属性和操作 B.信息流 C.消息和事件 D.数据的集合 2.状态图和活动图建立了UML面向对象开发过程中的对象动态(B)...
  • Java笔记—对象、类

    千次阅读 2019-11-15 18:47:09
    对象和类的概念对象对象是类的一个实例(实实在在存在的个体),有属性(状态)和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。 属性(property): 静态特征...
  • 类和面向对象习题

    万次阅读 2017-04-13 21:49:31
    3.4 精选习题 ...1.下列不属于面向对象编程的特性的是( )。 A.封装 B.继承 C.抽象 D.多态 2.(*)下述概念中不属于面向对象的是( )。 A.对象、消息 B.继承、多态 C.类、封装 
  • 面向对象考题收集

    千次阅读 2017-06-10 09:29:14
    3.下列不属于面向对象技术的基本特征的是( B )。 A. 封装性 B. 模块性 C. 多态性 D. 继承性
  • AI:人工智能概念之《Google发布机器学习术语表 (中英对照)》——持续更新ML、DL相关概念2018年4月! 相关文章AI:人工智能概念之《Google发布机器学习术语表 (中英对照)》——持续更新ML、DL相关概念2018年4月...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,909
精华内容 13,963
关键字:

下列关于对象概念描述错误的是