2.面向性能的设计与开发

原文:https://docs.oracle.com/cd/B19306_01/server.102/b14211/design.htm#g34949

最佳系统性能始于设计,并贯穿系统的整个生命周期。在初始设计阶段仔细考虑性能问题,在生产过程中更容易调整系统。
本章包含以下部分:
• Oracle方法论
• 了解投资选择
• 了解可伸缩性
• 系统架构
• 应用设计原则
• 负载测试,建模和实现
• 部署新应用程序

2.1 Oracle方法论

随着互联网在商业应用中发挥更大作用,计算机系统变得越来越大,越来越复杂,系统性能变得越来越重要。为了适应这种情况,Oracle基于多年的设计和性能经验制定了一套性能调优方法。该方法解释了如何可以显着提高系统性能,以及有哪些简单明了的活动。

性能调优战略的有效性各不相同,具有不同目的的系统 - 例如运营系统和决策支持系统 - 需要不同的性能调优技能。本书探讨了任何数据库设计人员,管理员或性能专家应该集中精力的注意事项。

性能问题通常是某些系统资源争用或耗尽的结果。当系统资源耗尽时,系统无法扩展到更高的性能级别。本文的性能调优方法,基于对数据库的仔细规划和设计,以防止系统资源耗尽并导致停机。通过消除资源冲突,可以使系统可扩展到业务所需的级别。

2.2 了解投资选择

随着相对便宜,高性能处理器,内存和磁盘驱动器的出现,人们倾向于购买更多系统资源来提高性能。在许多情况下,新的CPU,内存或更多磁盘驱动器确实可以立即改善性能。但是,通过添加硬件实现的任何性能提升都应被视为对即时问题的短期缓解。如果应用程序的需求和负载率继续增长,那么您很可能在不久的将来面临同样的问题。

在其他情况下,额外的硬件根本不会提高系统的性能。设计不良的系统无论分配多少额外硬件都表现不佳。在购买其他硬件之前,请确保应用程序中没有序列化或单线程。从长期来看,就每个业务事务使用的物理资源数量而言,提高应用程序的效率通常更有价值。

2.3 了解可伸缩性

可扩展性这个词在开发环境中的许多上下文中使用。以下部分提供了针对应用程序设计人员和性能专家的可伸缩性说明。
本节包括以下主题:
• 什么是可伸缩性?
• 系统可扩展性
• 影响可伸缩性的因素

2.3.1什么是可伸缩性?

可伸缩性是系统处理更多工作负载的能力,系统资源使用量成比例增加。换句话说,在可伸缩系统中,如果您将工作负载加倍,那么系统将使用两倍的系统资源。这听起来很明显,但由于系统内部存在冲突,资源使用量可能会超过原始工作负载的两倍。
由于资源冲突导致的可扩展性不佳的示例包括:
• 随着用户群增加,需要大量并发管理的应用程序
• 锁活动增加
• 增加了数据一致性工作量
• 增加了操作系统的工作量
• 随着数据量的增加,需要增加数据访问的事务
• 糟糕的SQL和索引设计导致返回相同行数的逻辑I / O数量更多
• 降低可用性,因为数据库对象需要更长的维护时间
如果应用程序将系统资源耗尽到在工作负载增加时无法实现吞吐量,则称该应用程序是不可扩展的。这样的应用导致吞吐量不可提升和较差的响应时间。
资源耗尽的示例包括以下内容:
• 硬件耗尽
• 大量事务处理时,表扫描导致不可避免的磁盘I / O短缺
• 网络请求过多,导致网络和调度瓶颈
• 内存分配导致分页和交换
• 过多的进程和线程分配导致操作系统抖动
这意味着应用程序设计人员必须创建一个不管用户群和数据量如何,使用的资源相同,并且不会将系统资源的负载超出其限制。

2.3.2系统可扩展性

可通过Internet访问的应用程序具有更复杂的性能和可用性要求。有些应用程序的设计和编写仅供Internet使用,但即使是典型的后台应用程序(如总帐应用程序),也可能需要在线提供部分或全部数据。
互联网时代应用的特征包括以下内容:
• 一年365天,每天24小时的可用性
• 不可预测且不精确的并发用户数
• 容量规划困难
• 任何类型查询的可用性
• 多层架构
• 无状态中间件
• 快速开发
• 测试时间最小化
图2-1显示了经典的工作负载增长曲线,需求以不断增长的速度增长。应用程序必须随着工作负载的增加而扩展,并且还需要添加额外的硬件以支持不断增长的需求。无论额外的硬件资源或重新设计工作如何,设计错误都可能导致实现达到极限。
图2-1工作量增长曲线
“图2-1工作量增长曲线”的描述
“图2-1工作量增长曲线”的描述

应用程序受到非常短的开发时间框架的挑战,测试和评估的时间有限。但是,糟糕的设计通常意味着在将来的某个时刻,系统需要重新设计或重新实施。如果在Internet上部署具有已知体系结构和实现限制的应用程序,并且如果工作负载超出预期需求,则将来确实存在失败的可能性。从业务角度来看,糟糕的表现可能意味着客户流失。如果Web用户在七秒内没有得到响应,那么用户的注意力可能会永远丢失。
在许多情况下,迁移到重构系统的停机成本超过正确构建原始系统的成本。故事的寓意很简单:从一开始就考虑到可扩展性的设计和实现。

2.3.3阻止可扩展性的因素

在构建应用程序时,设计人员和架构师应尽可能设计近完美的可扩展性。这有时被称为线性可扩展性,其中系统吞吐量与CPU数量成正比。
在现实生活中,线性可扩展性是不可能的,因为存在超出设计师控制的因素。但是,应该使应用程序尽可能的扩展到可通过扩展硬件组件和新CPU技术来实现当前和未来的性能目标。
可能妨碍线性可扩展性的因素包括:
• 应用程序设计,实现和配置不佳
应用程序对可伸缩性的影响最大的因素有:
o 糟糕的架构设计可能导致昂贵的SQL无法扩展。
o 糟糕的事务设计可能导致锁和序列化问题。
o 连接管理不良可能导致响应时间较长和系统不可靠。
但是,设计并不是唯一的问题。应用程序的物理实现也可能是薄弱环节,例如:
o 系统迁移到具有错误I / O策略的生产环境。
o 生产环境使用了与测试中生成的执行计划不同的执行计划。
o 给内存密集型应用程序分配大量内存,而不考虑在运行时释放内存,由此可能会导致内存溢漏。
o 低效的内存使用和内存溢漏给操作虚拟内存子系统带来了很大的压力。这会影响性能和可用性。
• 硬件组件的大小调整不正确
随着相对硬件价格的下降,硬件组件容量规划变得越来越不成问题。但是,当系统的工作负载增加时,过多的容量会掩盖可伸缩性问题。
• 软件组件的局限性
所有软件组件都具有可伸缩性和资源使用限制。这适用于应用程序服务器,数据库服务器和操作系统。应用程序设计不应对软件提出超出其可处理范围的要求。
• 硬件组件的限制
硬件不是完全可扩展的。大多数多处理器系统可以通过有限数量的CPU接近线性扩展,但是在某一点之后,每个额外的CPU虽然可以提高整体性能,但不是成比例的。可能有一段时间,额外的CPU不会提高性能,甚至会降低性能。此行为与工作负载和操作系统设置密切相关。
注意:
这些因素来自于Oracle Server Performance小组在调优不可扩展系统时的经验。

2.4系统架构

系统架构有两个主要部分:
• 硬件和软件组件
• 根据需求配置正确的系统架构

2.4.1硬件和软件组件

本节讨论硬件和软件组件。

2.4.1.1硬件组件

当今的设计师和架构师负责多层环境中每层的硬件规模和容量规划。架构师的责任是平衡各种问题。这类似于桥梁设计师,他必须考虑桥梁的所有各种有效载荷和结构要求。桥梁的承载能力取决于最薄弱的部分。因此,桥梁设计要平衡所有组件同时达到其极限。
主要硬件组件包括:
• 中央处理器
• 内存
• I / O子系统
• 网络

2.4.1.1.1 CPU

可以有一个或多个CPU,它们的处理能力可以从手持设备中的简易CPU到高功率服务器CPU。其他硬件组件的大小通常是基于多CPU的系统。请参见第9章“了解操作系统资源”。

2.4.1.1.2 内存

数据库和应用程序服务器需要大量内存来缓存数据并避免耗时的磁盘访问。请参见第7章“内存配置和使用”。

2.4.1.1.3 I / O子系统

I / O子系统包括客户端PC上的硬盘,到高性能磁盘阵列之间。磁盘阵列每秒可以执行数千个I / O,并通过多个I / O路径和热插拔镜像磁盘冗余提供可用性。请参见第8章“I / O配置和设计”。

2.4.1.1.4网络

系统中的所有计算机都连接到网络,从调制解调器线路到高速LAN。网络规范的主要问题是带宽(容量)和延迟(速度)。

2.4.1.2软件组件

与具有通用硬件组件的方式相同,应用程序也具有通用功能组件。将软件开发划分为功能组件,可以更好地理解应用程序设计和体系结构。系统的某些组件可以通过购买现有软件,以加速应用程序的实现,或避免重复开发通用组件。
软件组件和硬件组件之间的区别在于,硬件组件仅执行一项任务,但一个软件可以执行多种任务。例如,磁盘驱动器仅存储和检索数据,但客户端程序可以管理用户界面并执行业务逻辑。
大多数应用程序涉及以下组件:
• 管理用户界面
• 实施业务逻辑
• 管理用户请求和资源分配
• 管理数据和事务

2.4.1.2.1管理用户界面

该组件对应用程序用户最为明显。这包括以下功能:
• 在用户面前绘制屏幕
• 收集用户数据并将其传输到业务逻辑
• 验证数据输入
• 控制应用程序的级别或状态

2.4.1.2.2实现业务逻辑

该组件实现核心业务规则,是应用程序功能的核心。修该此组件中的错误可能非常昂贵。该组件同时使用声明式和过程式两种实现方法。声明式活动的一个示例是定义唯一键和外键。基于过程的逻辑的一个示例,如实施折扣策略。
该组件的通用功能包括:
• 将数据模型保存到关系型表结构
• 在关系型表结构中定义约束
• 编写程序逻辑以实现业务规则

2.4.1.2.3管理用户请求和资源分配

所有软件中都有该组件的实现。但是,有些请求和资源可能会受到应用程序设计的影响。
在多用户应用程序中,用户请求的大多数资源分配由数据库服务器或操作系统处理。但是,在用户数量及其使用模式未知或快速增长的大型应用程序中,系统架构师必须主动确保没有某个软件组件过载或不稳定。
该组件的通用功能包括:
• 与数据库的连接管理
• 有效执行SQL(游标和SQL共享)
• 管理客户端状态信息
• 平衡跨硬件资源的用户请求负载
• 设置硬件/软件组件的运维目标
• 持久化队列以执行异步任务

2.4.1.2.4管理数据和事务

该组件主要由数据库服务器和操作系统负责。
该组件的通用功能包括:
• 使用锁和事务语义提供对数据的并发访问
• 使用索引和内存缓存提供对数据的优化访问
• 确保在发生硬件故障时记录数据更改
• 执行(为某数据定义的)规则

2.4.2根据需求配置正确的系统架构

配置初始系统架构很大程度上是一个迭代的过程。架构师必须在预算和进度限制内满足系统要求。如果系统要求交互式用户根据数据库的内容处理业务决策,那么用户需求就会驱动架构。如果系统上的交互式用户很少,那么该体系结构是由流程驱动的。
交互式用户应用程序示例:
• 会计和簿记应用程序
• 订单输入系统
• 电邮服务器
• 基于Web的零售应用程序
• 交易系统
流程驱动的应用程序示例:
• 计费系统
• 欺诈检测系统
• 直邮
在许多方面,流程驱动的应用程序比多用户应用程序更容易设计,因为消除了用户界面元素。但是,由于目标是面向流程的,因此不习惯处理大量数据和不同成功因素的架构师可能会感到困惑。流程驱动的应用程序来自基于用户的应用程序和数据仓库中使用的技能集。因此,本书侧重于不断发展的交互式用户系统架构。
注意:
创建系统架构不是一个确定性过程。它需要仔细考虑业务需求,技术选择,现有基础设施和系统,以及实际物理资源,如预算和人力。
以下问题可以激发对架构的思考,尽管它们不是系统架构的权威指南。这些问题演示了业务需求如何影响体系结构,实现的简单化以及系统的整体性能和可用性。例如:
• 系统支持多少用户?
大多数应用程序属于以下类别之一:
o 使用频率低或专用的系统,用户很少
对于这种类型的应用程序,通常有一个用户。应用程序设计的重点是通过提供良好的响应时间使单个用户尽可能高效,同时使应用程序需要最少的运维。这些应用程序的用户很少相互干扰,并且资源冲突最小。
o 企业共享应用程序,有中型到大型的用户群
对于这种类型的应用程序,用户数量受到公司中使用系统的员工数量的限制。因此,用户数量是可预测的。但是,提供可靠的服务对业务至关重要。用户将使用共享资源,因此设计必须解决在繁重的系统负载下的响应时间,每个会话使用的资源增长,以及未来增长的空间。
o Internet上的无限用户群
对于此类应用,需要额外的工程以确保没有系统组件超出其设计限制。这将产生瓶颈,使系统停止并变得不稳定。这些应用程序需要复杂的负载平衡,无状态应用程序服务器和高效的数据库连接管理。此外,如果由于系统过载而无法满足其请求,则应使用统计信息和调控器来确保用户获得一些反馈。
• 什么是用户交互方法?
用户界面的选择范围从简单的Web浏览器到自定义客户端程序。
• 用户在哪里?
用户之间的距离会影响应用程序的设计方式,以应对网络延迟。该位置还会影响一天中的哪些时间繁忙,此时间段将无法执行批处理或系统维护功能。
• 什么是网络速度?
网络速度会影响数据量,以及用户界面与应用程序和数据库服务器的交互质量。高度交互的用户界面需要在每个键击或字段级验证时与后端服务器通信。较少交互的界面适用于页面发送和页面接收模型。在慢速网络上,使用高度交互的用户界面无法实现高数据输入速度。
• 用户可以访问多少数据,以及有多少数据主要是只读的?
在线查询的数据量会影响设计的所有方面,从表格和索引设计到表示层。设计工作必须确保用户响应时间不随数据库大小而变。如果应用程序基本上是只读的,则复制和数据分发到应用程序服务器中的本地缓存成为可行的选择。这也减少了数据库的工作负载。
• 用户响应时间需求是什么?
考虑用户类型很重要。如果用户是位高层执行官,需要准确信息做出快速决策,那么用户响应时间就不能妥协。其他类型的用户(例如执行数据输入活动的用户)可能不需要如此高的性能水平。
• 用户是否期望24小时服务?
这对于当今24小时交易的互联网应用是强制性的。但是,在单个时区中运行的公司系统可能能够容忍非工作时间的停机时间。此非工作时间停机时间可用于运行批处理或执行系统管理。在这种情况下,不运行完全可用的系统可能更经济。
• 所有变更都必须实时进行吗?
确定是否需要在用户响应时间内完成事务,或者是否可以将它们排队等待异步执行非常重要。
以下是次要问题,这些问题也可能影响设计,但实际上对预算和实施的简易性有更大的影响。例如:
• 数据库有多大?
这会影响数据库主机系统的大小。在具有非常大的数据库的系统上,可能需要具有比工作负载所规定的更大的系统。这是因为大型数据库的管理开销很大程度上取决于数据库大小。随着表和索引的增长,需要更多的CPU在可接受的时间限制内完成表重组和索引构建。
• 业务交易所需的吞吐量是多少?
• 有哪些可用性要求?
• 是否存在构建和管理此应用程序的技能?
• 预算限制将迫使哪些妥协?

2.5应用设计原则

本节介绍构建应用程序时涉及的以下设计决策:
• 应用程序设计的简单性
• 数据建模
• 表和索引设计
• 使用视图
• SQL执行效率
• 应用程序实现
• 应用程序开发的趋势
2.5.1应用程序设计的简单性
应用程序与任何其他设计和工程产品没有什么不同。精心设计的结构,系统和工具通常可靠,易于使用和维护,并且概念简单。从最一般的角度来看,如果设计看起来正确,那么可能就是这样。在构建应用程序时,应始终牢记这一原则。
考虑以下一些设计问题:
• 如果表设计过于复杂以至于没有人能够完全理解它,那么该表可能设计得很差。
• 如果SQL语句太长且涉及到任何优化器都不可能实时有效地优化它,那么可能存在不好的语句,事务或表设计。
• 如果表上有索引并且重复索引相同的列,那么索引设计可能很差。
• 如果提交的查询时,没有适当措施来对在线用户进行快速响应,那么可能存在糟糕的用户界面或事务设计。
• 如果对数据库的调用从应用程序逻辑中抽象出来多层,那么可能存在糟糕的软件开发方法。

2.5.2数据建模

数据建模对于成功的关系型应用程序设计很重要。数据建模应该快速表达业务实践。很可能会有关于正确数据模型的热烈争论。重要的是将最大的建模工作集中在最频繁业务处理的实体上。在建模阶段,很有可能花费太多时间来建模非核心数据元素,这导致开发时间的增加。使用建模工具可以快速生成模式定义,在需要快速原型时非常有用。

2.5.3表和索引设计

表设计在很大程度上是核心事务的灵活性和性能之间的折衷。为了使数据库保持灵活性并能够适应不可预见的工作负载,表格设计应该与数据模型非常相似,并且应该将其标准化为至少第3范式。但是,用户所需的某些核心事务可能需要非规范化以实现性能目的。
此技术的示例包括存储预先连接的表,添加派生列和聚合值。Oracle通过集群和物化视图功能提供了许多用于存储聚合和预加入数据的选项。这些功能允许最初采用更简单的表格设计。
总之,应将重点和资源用于业务关键表,以便实现最佳性能。对于非关键表,可以采用设计中的快捷方式来实现更快速的应用程序开发。但是,如果原型设计和测试非核心表成为性能问题,则应立即应用补救设计工作。
索引设计也是一个迭代的过程,它是基于应用程序设计者生成的SQL。构建强制主键约束的索引和已知访问模式的索引(例如人名)是明智的开始。通过改进应用程序和对实际数据量的测试来构建更好的索引,以便让某些查询的性能得到改进。在构建新索引时,应考虑以下因素:
• 将列加到索引或使用索引组织表
• 使用不同的索引类型
• 寻找索引成本
• 在索引中序列化
• 索引中对列排序

2.5.3.1将列加到索引或使用索引组织表

加速查询的最简单方法之一是通过消除执行计划中的表访问来减少逻辑I / O的数量。这可以通过将查询引用的所有列附加到索引来完成。这些列是select列表列以及任何join或排序列。当耗时的I / O减少时,此技术对于加快在线应用程序响应时间特别有用。应该先用适当大小的数据测试应用程序。
更激进的方法是构建一个索引组织表(IOT)。但是,您必须小心确保IOT增加的叶子大小不会破坏减少I / O的努力。
2.5.3.2使用不同的索引类型
有几种可用的索引类型,每种索引对某些情况有好处。以下列表提供了与每种索引类型相关的性能提示。

2.5.3.2.1 B树索引

这些索引是标准索引类型,它非常适合主键和高选择性(highly-selective,该列的数据值大多都不相同)的索引。作为复合索引,B树索引可用于检索由多索引列排序的数据。

2.5.3.2.2位图索引

此类索引适用于数据值种类少的列(如性别)。通过压缩技术,它们可以生成大量具有最小I / O的rowid。在多个非选择性(non-selective,值基本相同)列上使用位图索引,可以使用大量的rowid进行高效AND和OR操作,并且I / O最小。位图索引在使用COUNT()的查询中特别有效,因为查询可以在索引中完成。

2.5.3.2.3 基于功能的索引

此类索引允许通过B树访问从使用基础数据的函数派生的值。基于函数的索引在使用空值方面有一些限制,它们要求您启用查询优化器。
在查询复合列以生成派生结果,或克服存储在数据库中的数据限制时,基于函数的索引特别有用。例如,查询订单中的订单项超过从(销售价格 - 折扣)x数量 派生的特定值,其中这些是表格中的列。另一个示例是将UPPER函数应用于不区分大小写的搜索。

2.5.3.2.4 分区索引

对全局索引进行分区从而减少I / O. 定义好范围或列表分区,定位某个索引分区,可以加速索引的扫描,减少查询时间。

2.5.3.2.5 反向键索引

此类索引旨在消除插入程序上的索引热点。这些索引非常适合插入性能,但它们的局限性在于它们不能用于索引范围扫描。

2.5.3.3 查找索引成本

构建和维护索引结构可能很昂贵,并且可能消耗诸如磁盘空间,CPU和I / O容量之类的资源。设计师必须确保索引带来的好处超过索引维护的负面影响。
索引维护成本简单估算指南:每个带索引的INSERT,DELETE或UPDATE所需要的资源,大约是对表的DML操作所需要的资源的三倍。这意味着如果你INSERT进入一个有三个索引的表,那么它将比INSERT没有索引的表慢大约10倍。对于DML,特别是对于INSERT重型应用程序,应该认真审查索引设计,这可能需要在查询和INSERT性能之间进行折衷。
有关监视索引使用情况的信息,请参见 Oracle数据库管理员指南

2.5.3.4 在索引中序列化

使用序列或时间戳来生成自身索引的键值可能会导致数据库热点问题,从而影响响应时间和吞吐量。这通常是单调增长key导致右向增长索引(right-growing index)的结果。要避免此问题,请尝试生成的键值插入在索引的全区间内,这会平衡索引,让索引更具可扩展性和效率。您可以通过使用反向键索引或使用循环序列来设置前缀和序列值来实现此目的。

2.5.3.5 对索引中的列进行排序

设计人员应该灵活地定义索引构建的规则。根据您的具体情况,使用以下两种方法之一对索引中的键进行排序:
• 首先排序选择性最多的列(也就是其值最不同的列)。此方法是最常用的方法,因为它提供了最快的访问速度,并且对所需的实际rowid具有最小的I / O. 该技术主要用于主键和very selective的区间扫描。
• 通过对数据进行聚类或排序来对列进行排序以减少I / O. 在大区间扫描中,通常可以通过以最小选择(the least selective)顺序对列进行排序,或者以按照应该检索的方式对数据进行排序的方式来减少I / O. 请参见第15章“使用索引和群集”。

2.5.4 使用视图

视图可以加速并简化应用程序设计。简单的视图定义可以降低数据模型的复杂性,让程序员的优先级集中在检索,显示,收集和存储数据。
但是,虽然视图提供了干净的编程接口,但它们可能会导致 sub-optimal资源密集型查询。最糟糕的视图使用类型是视图引用其他视图并且它们在查询中使用join的情况。在许多情况下,开发人员可以直接从表中查询到结果而无需使用视图。通常,由于其固有属性,视图使优化器难以生成最佳执行计划。

2.5.5 SQL执行效率

在任何系统开发的设计和架构阶段,都应该注意确保应用程序开发人员了解SQL执行效率。为此,开发环境必须支持以下特征:
• 良好的数据库连接管理
连接到数据库是一项昂贵的操作,非常不可扩展。因此,应尽可能减少与数据库的并发连接数。在应用程序初始化时就建立用户连接是最理想的。但是,在基于Web或多层应用程序中,应用程序服务器通常使用多路复用数据库连接给用户,上述实现会很困难。因此设计这些类型的应用程序时,应确保创建数据库连接池,并且不要为每个用户请求重新建立连接。
• 良好的光标使用和管理
最小化解析活动与维护用户连接同样重要。解析是解释SQL语句并为其创建执行计划的过程。此过程包含许多阶段,包括语法检查,安全检查,执行计划生成以及将共享结构加载到共享池中。有两种类型的解析操作:
o 硬解析:第一次提交SQL语句,在共享池中找不到相同的SQL匹配。硬解析是资源最密集且不可扩展的,因为它执行解析中涉及的所有操作。
o 软解析:第一次提交SQL语句,在共享池中发现相同的SQL匹配。匹配可能是其他用户先前执行的结果。SQL语句是共享的,这有利于提高性能。但是,软解析并不理想,因为它们仍然需要语法和安全检查,这会消耗系统资源。
解析应尽可能地最小化,因此应用程序开发人员应设计为解析SQL语句一次,并执行多次。这是通过游标完成的。经验丰富的SQL程序员应该熟悉打开和重新执行游标的概念。
应用程序开发人员还必须确保在共享池中共享SQL语句。为此,请绑定变量以表示不同的查询时更改的部分。如果不这样做,则SQL语句可能会被解析之后永远不会被其他用户重用。要确保共享SQL,请使用绑定变量,不要将字符串文字与SQL语句一起使用。例如:
字符串文字的声明:

SELECT * FROM员工 
  WHERE last_name LIKE'KING';

绑定变量的语句:

SELECT * FROM员工 
  WHERE last_name LIKE:1;

以下示例显示了对简单OLTP应用程序的测试结果:
测试 #支持的用户数
不解析所有SQL语句 270
Soft解析所有SQL语句 150
硬解析所有SQL语句 60
每个事务处理的重新连接 30
这些测试是在四个CPU系统上进行的。随着系统上CPU数量的增加,差异也会增加。有关优化SQL语句的信息,请参见第11章“SQL调优概述”。

2.5.6应用程序实现

开发环境和编程语言的选择在很大程度上取决于开发团队的技能,以及架构决策。但是,有一些简单的性能管理规则可以帮助实现可扩展的高性能应用程序。

  1. 选择适合软件组件的开发环境,不要让它限制您关于性能决策的设计。如果是,那么您可能选择了错误的语言或环境。
    o 用户界面
    编程模型可以是HTML或者直接调用窗口系统。开发方法应该关注用户界面代码的响应时间。如果通过网络发送HTML或Java,请尝试最小化网络流量和交互。
    o 业务逻辑
    解释型语言(例如Java和PL / SQL)是编写业务逻辑的理想选择。它们便携,使逻辑变更相对容易。两种语言在语法上都很丰富,易于阅读和理解。如果业务逻辑需要复杂的数学函数,则可能需要编译语言(如C)。业务逻辑代码可以位于客户端,应用服务器和数据库服务器上。但是,应用服务器是业务逻辑最常见的位置。
    o 用户请求和资源分配
    用户请求和资源分配基本不受编程语言的影响,但封装数据库连接和游标管理的工具和第4代语言可能会使用低效的机制。在评估这些工具和环境时,请检查其数据库连接模型及其对游标和绑定变量的使用。
    o 数据管理和事务处理
    数据管理和事务处理基本不受编程语言的影响。
  2. 实现组件时,请实现其自己的功能,而不是与其他组件相关的功能。实现另一个组件的功能会导致次优设计和实现。这适用于所有组件。
  3. 不要留下功能缺陷,或在设计,实现或测试中使用还在验证的组件。在许多情况下,缺陷在应用程序发布之前,或在实际环境进行测试之前,不会被发现。这通常是架构不佳或初始系统规范的信号。在初始系统设计,构建和实施过程中,数据归档/清除模块最常被忽略。
  4. 在实现过程逻辑时,使用过程语言,例如C,Java或PL / SQL。在实现数据访问(查询)或数据更改(DML)时,请使用SQL。此规则特定于业务逻辑模块代码,其中过程代码与数据访问(非过程SQL)代码混合使用。虽然将过程逻辑放入SQL访问中有很大的诱惑力,但这往往会导致资源密集SQL的性能不佳。带有DECODE case语句的SQL语句,以及具有大量OR或带有UNION和MINUS的set运算符的SQL语句,通常都需要优化。
  5. 尽量访问缓存,避免更改重复检索的数据。但是,要确保缓存机制易于使用,并确保它确实比用原始方法访问数据便宜。这适用于应在本地缓存或存储常用数据值的所有模块,而不是从远程或昂贵的数据存储中重复检索。
    本地缓存最常见的使用场景包括:
    o 当天的日期。SELECT SYSDATE FROM DUAL可以占数据库工作量的60%以上。
    o 当前用户名。
    o 重复的应用程序变量和常量,例如税率,折扣率或位置信息。
    o 本地缓存数据可以进一步扩展到在应用服务器中间层中构建本地数据缓存。这有助于减轻中央数据库服务器的负担。但是,在构建本地缓存时应小心谨慎,避免它们不会变得过于复杂,以至于不能提供性能提升。
    o 本地序列生成(local sequence generation)。
    应考虑如何设计缓存的更新。例如,如果用户在午夜登录,而前一日的日期被缓存的话,则用户的日期值将变为无效。
  6. 优化组件之间的接口,并确保在最可扩展的配置中使用所有组件。此规则需要易于理解,并适用于所有模块及其接口。
  7. 使用外键引用。通过应用程序实现引用完整性是昂贵的。您可以通过从父表中select子表的列值并确保它的存在来维护外键引用。Oracle提供的外键约束实施(不使用SQL)快速,易于声明,并且不会有网络流量。
  8. 考虑在应用程序中设置操作和模块名称,这些名称可以用在端到端应用程序跟踪中。这样可以更灵活地跟踪工作负载问题。请参阅“端到端应用程序跟踪”。

2.5.7 应用程序开发趋势

当今应用程序开发面临的两大挑战是,越来越多地使用Java来替换C或C++等编译语言,并且增加了面向对象技术的使用,从而影响了架构设计。
Java为程序员提供了更好的代码可移植性和可用性。但是,Java存在许多与性能相关的问题。由于Java是一种解释型语言,因此执行相同逻辑的速度比C等编译语言慢。因此,客户端系统的资源使用量会增加。这需要在客户端或中间层系统中应用更强大的CPU,并且程序员需要更加谨慎地编写有效代码。
由于Java是面向对象的语言,因此它鼓励将数据访问绝缘到不执行业务逻辑的类中。结果,程序员可能在不知道所使用的数据访问效率的情况下调用某个方法。这往往导致数据库访问非常小,并使用最简单粗暴的数据库接口。
使用这种类型的软件设计,查询并不总是带有效的WHERE语句,并且行过滤在Java程序中执行。这是非常低效的。此外,对于DML操作 - 特别是对于数据插入,执行多次单个INSERT,不可能使用Array接口。在某些情况下,过程调用会使效率降低。与实际数据库调用相比,将数据移入和移出数据库使用更多资源。
通常,最好将数据访问调用放在业务逻辑的旁边,以实现最佳的整体事务设计。
在编程级别接受面向对象已导致在Oracle Server中创建面向对象的数据库。这在许多方面表现出来,从在BLOBs中存储对象结构并且仅将数据库有效地用作indexed card文件到使用Oracle对象关系特征。
如果采用面向对象的方法进行模式设计,那么请确保不会失去关系存储模型的灵活性。在许多情况下,面向对象的模式设计方法最终导致严重非规范化的数据结构,需要大量的维护和与对象相关的REF指针。通常,这些设计是用关系存储方法取代的分层和网络数据库设计的某种倒退。
总之,如果您将数据长期存储在数据库中并预期在同一模式上进行特定查询或应用程序开发,那么您可能会发现关系型存储方法提供了最佳性能和灵活性。

2.6 负载测试,建模和实现

本节介绍工作负载估计,建模,实现和测试。本节包括以下主题:
• 数据sizing
• 估算负载
• 应用程序建模
• 测试,调试和验证设计

2.6.1 数据sizing

如果使用较差的样本集,在处理可变长度数据时,您可能会遇到sizing估计值的错误。随着数据量的增长,您的键长度可能会大幅增长,从而改变您对列大小的假设。
当系统运行时,预测数据库增长变得更加困难,特别是索引。表随着时间的推移而增长,并且索引在键生成,插入模式和行删除方面受到应用程序个别行为的影响。最糟糕的情况是使用升序键插入,然后从左侧删除大多数行但不删除所有行。这留下了空隙和浪费的空间。如果你有这样的索引使用,请确保你知道如何使用在线索引重建工具。
DBA应监视每个对象的空间分配,并查找可能增长失控的对象。对应用程序的良好理解可以突出快速或不可预测地增长的对象。这是任何系统的性能和可用性规划的关键部分。在实现生产数据库时,设计应尝试确保在交互式用户使用应用程序时进行最小的空间管理。这适用于所有数据,临时和回滚段。

2.6.2 估算负载

用于容量规划和测试目的的负载估算通常被描述为黑色艺术。在考虑所涉及的变量数量时,很容易理解为什么这个过程在很大程度上不可能精确正确。但是,设计人员需要为系统指定CPU,内存和磁盘驱动器,并最终发布应用程序。有许多技术用于确定sizing,每种技术都有其优点。sizing时,最好使用以下两种方法来验证您的决策过程并提供支持文档:
• 从类似系统推断
• 基准

2.6.2.1 从类似系统推断

这是一种完全靠经验的方法,具有相似特征和已知性能的现有系统被用作基础系统。然后,估算专家根据已知的差异修改规格。这种方法的优点在于它与现有系统相关,但在处理差异时几乎没有提供帮助。
在准备工程项目的成本时,这种方法几乎用于所有大型工程学科(例如大型建筑物,船舶,桥梁或石油钻井平台)。如果参考系统的大小与预期系统的大小不同,则某些组件可能已超出其设计限制。

2.6.2.2 基准测试(Benchmarking)

基准测试过程既耗费资源又耗时,并且可能无法产生正确的结果。通过在早期开发或原型中模拟应用程序,存在测量与实际生产系统无关的危险。这听起来很奇怪,但在多年来使用数据库开发组织对客户应用程序进行基准测试时,Oracle尚未看到基准应用程序与实际生产系统之间的可靠关联。这主要是由于开发过程中引入了效率低下的应用程序。
但是,基准测试已成功用于将系统估算到可接受的精确范围。特别是,基准测试非常擅长确定系统满载时的实际I / O要求和测试恢复过程。
基准是所有系统组件的极限。由于所有组件都受到压力,因此在基准测试时能看到应用程序设计和实现中的所有错误。基准测试还测试数据库,操作系统和硬件组件。由于大多数基准测试都是匆忙执行的,因此在系统组件发生故障时会出现缺陷和问题。基准测试是一项压力很大的活动,需要相当多的经验才能充分利用基准测试。

2.6.3应用程序建模

应用程序建模的范围可以从复杂的数学建模到简单计算。这两种方法都有其优点,一种方法试图非常精确,另一种方法估计总量。这两种方法的缺点是它们不允许实现错误和低效率。
估算和sizing过程是不精确的。但是,通过调查过程,可以得到一些智能估算。整个估算过程不允许因不良SQL,索引设计或游标管理引入的应用程序效率低下。sizing工程师应该为应用程序效率低下预留一些资源。性能工程师应该发现效率低下并使估算看起来很现实。Oracle性能方法中描述了发现应用程序低效的过程。

2.6.4测试,调试和验证设计

测试过程主要包括功能和稳定性测试。在该过程的某个阶段,执行性能测试。
以下列表描述了一些用于应用程序性能测试的简单规则。如果记录正确,这将为应用程序上线后的生产应用程序和容量规划过程提供重要信息。
• 使用 Automatic Database Diagnostic Monitor (ADDM)和SQL Tuning Advisor进行设计验证
• 使用实际数据量和分布进行测试
所有测试必须使用完全填充的表完成。测试数据库应包含代表生产系统的数据,包括表之间的数据量和关系。应构建所有生产索引,并正确填充模式统计信息。
• 使用正确的优化器模式
应使用将在生产中使用的优化器模式执行所有测试。Oracle的所有研发工作都集中在查询优化器上,因此建议使用查询优化器。
• 测试单个用户的性能
应对空闲或轻度使用的系统上的单个用户进行可接受性能测试。如果单个用户在理想条件下无法达到可接受的性能,则在共享资源的多个用户下不可能有可接受的性能。
• 获取并记录所有SQL语句的计划
获取每个SQL语句的执行计划,并且应该至少执行一次语句获取一些度量标准。此过程应用于验证优化程序是否已获取最佳执行计划,并且可以根据CPU时间和物理I / O来理解SQL语句的相对成本。此过程有助于识别将来需要进行大量调整和性能工作的事务。有关计划稳定性的信息,请参见第18章“使用计划稳定性”。
• 尝试多用户测试
此过程难以准确执行,因为用户的工作负载可能无法完全量化。但是,应测试执行DML语句的事务以确保不存在锁冲突或序列化问题。
• 使用正确的硬件配置进行测试
使用尽可能靠近生产系统的配置进行测试非常重要。这对于网络延迟,I / O子系统带宽以及处理器类型和速度尤其重要。如果不这样做,可能会导致对潜在性能问题的错误分析。
• 测量稳态性能
在进行基准测试时,在稳态条件下测量性能非常重要。每个基准测试运行应该有一个预热阶段,用户连接到应用程序并逐渐开始执行应用程序的工作。此过程允许将频繁缓存的数据初始化到缓存中,并且单个执行操作(例如解析)在稳态条件之前完成。同样,在基准测试运行结束时,应该有一个减速期,资源从系统中释放出来,用户停止工作和断开连接。

2.7 部署新应用程序

本节介绍了部署应用程序时涉及的以下设计决策:
• 发布策略
• 性能检查表

2.7.1 发布策略

当推出新的应用程序时,通常采用两种策略:
• Big Bang方法 - 所有用户立即迁移到新系统
• Trickle方法 - 用户从现有系统缓慢迁移到新系统
这两种方法都有优点和缺点。Big Bang方法依赖于在所需规模下对应用程序的可靠测试,但具有数据转换最小化和与旧系统同步的优势,只需关闭旧系统。Trickle方法允许在负载增加时调试可伸缩性问题,但在迁移阶段,可能需要将数据迁移到遗留系统和从遗留系统迁移出。
很难推荐采用哪一种方法,因为每种方法都存在相关风险,可能会在转换发生时导致系统中断。当然,Trickle方法允许在引入新应用程序时对真实用户进行分析,并允许重新配置系统,同时仅影响迁移的用户。这种方法会影响早期采用者的工作,但会限制支持服务的负担。这意味着计划外中断仅影响一小部分用户。
关于如何发布新应用程序是根据不同的业务来决定的。采用的方法将有其独特的外部压力和内部压力。从测试中获得的信息越多,您就越能情况哪种方法最适合。

2.7.2 性能检查表

为了协助发布过程,构建一个任务列表 - 如果正确执行 - 将增加生产中最佳性能的可能性 - 如果存在问题,则启用应用程序的快速调试:

  1. 当您创建生产数据库的控制文件时,为MAXINSTANCES,MAXDATAFILES,MAXLOGFILES,MAXLOGMEMBERS,和MAXLOGHISTORY设置比预期更高的值。这会导致更多的磁盘空间使用和更大的控制文件,但如果在紧急情况下需要扩展,则可以节省时间。
  2. 将块大小设置为用于开发应用程序的值。如果在与实际相当的数据量上执行测试并且SQL执行正确,则将schema统计信息从开发/测试环境导出到生产数据库。
  3. 设置最小数量的初始化参数。理想情况下,大多数其他参数应保留为默认值。如果要执行更多调优,则应在系统出现性能问题时考虑。有关初始实例配置中参数设置的信息,请参见第4章“为性能配置数据库”。
  4. 通过设置数据库对象的存储选项来管理块争用。如果INSERT/ UPDATE/ DELETE使用频繁,应用自动段空间管理创建表和索引。为避免回滚段的争用,应使用自动撤消(undo)管理。有关撤消和临时段的信息,请参见第4章“为性能配置数据库”。
  5. 应验证所有SQL语句是否最优并了解其资源使用情况。
  6. 验证连接到数据库的中间件和程序在连接管理中是否有效,并且不会重复登录/注销。
  7. 验证SQL语句是否有效地使用游标。每个SQL语句应解析一次,然后执行多次。没有达到这种效果最常见的原因是,没有使用绑定变量,而是在WHERE子句里使用了字符串文字。如果使用预编译器来开发应用程序,那么确保参数MAXOPENCURSORS,HOLD_CURSOR以及RELEASE_CURSOR已经从之前的默认值重置为预编译应用程序。
  8. 验证所有模式对象是否已从开发环境正确迁移到生产数据库。这包括表,索引,序列,触发器,包,过程,函数,Java对象,synonyms,grants和视图。确保在测试环境做的任何修改都反应到生产环境。
  9. 系统发布后,立即建立一组统计信息基线,该统计信息包括来自与数据库与操作系统。这是第一组统计信息,可以验证和纠正在设计和部署过程所做的任何假设。
  10. 开始预测第一个瓶颈(总会有一个瓶颈)并遵循Oracle性能方法来提高性能。有关详细信息,请参阅第3章“性能改进方法”。

猜你喜欢

转载自blog.csdn.net/weixin_40165747/article/details/82944961
今日推荐