说明:本文为面向Oracle数据库应用设计原理初学者的指导手册
标签:数据库架构、架构设计、Oracle优化、架构师
用途:帮助你设计出更加高效和可靠的数据库应用架构
易学:文中删去了不需要的多余部分,让初学者一目了然一学就会
温馨提示:如果您发现本文哪里写的有问题或者有更好的写法请留言或私信我进行修改优化
★ 相关文档
※ Oracle官方文档(21c)
应用设计原理
应用程序设计简单
应用程序与任何其他设计和制造的产品没有什么不同。设计良好的结构,计算机和工具通常可靠,易于使用和维护且概念简单。用最笼统的术语来说,如果设计看起来正确,则可能是正确的。构建应用程序时应始终牢记这一原则。
请考虑以下设计问题:
-
如果表格设计过于复杂,以至于没人能完全理解它,那么表格的设计可能就很糟糕。
-
如果SQL语句太长且涉及太多,以至于任何优化程序都不可能实时有效地对其进行优化,则可能存在错误的语句,基础事务或表设计。
-
如果表上有索引,并且相同的列被重复索引,则可能是不良的索引设计。
-
如果提交的查询没有在线用户快速响应的适当资格,则可能是用户界面或交易设计不佳。
-
如果通过多层软件从应用程序逻辑中抽象出对数据库的调用,则可能是一种不良的软件开发方法。
表和索引设计
表设计在很大程度上是灵活性和核心事务性能之间的折衷。为了保持数据库的灵活性并能够容纳不可预见的工作负载,表设计应与数据模型非常相似,并且应规范化为至少第三范式。但是,出于性能目的,用户所需的某些核心事务可能需要选择性地进行非规范化。
此技术的示例包括存储预先连接的表,添加派生列和聚合值。Oracle数据库通过集群和实例化视图功能提供了多种存储聚合和预联接数据的选项。这些功能使最初可以采用更简单的表设计。
同样,应将重点和资源用于关键业务表,以便获得最佳性能。对于非关键表,可以采用设计中的快捷方式来实现更快的应用程序开发。但是,如果原型设计和测试非核心表成为性能问题,则应立即采取补救性设计工作。
基于应用程序设计人员生成的SQL,索引设计在很大程度上也是一个迭代过程。但是,可以通过建立强制执行主键约束的索引和基于已知访问模式(例如人名)的索引来明智地开始。随着应用程序的发展以及对实际数据量的测试,您可能需要通过构建更好的索引来提高特定查询的性能。构建新索引时,请考虑以下索引设计思想列表:
使用其他索引类型
有几种可用的索引类型,每种索引在某些情况下都有好处。下表列出了与每种索引类型相关的性能思想。
位图索引
这些索引适用于具有相对较少数量的不同值的列,在这些列中添加B树索引的好处可能会受到限制。这些索引适用于DML活动低和临时过滤模式的数据仓库应用程序。在列合并位图索引实现高效AND
和OR
用最少的I / O操作。此外,通过压缩技术,它们可以使用最少的I / O生成大量的rowid。位图索引在使用进行查询时特别有效COUNT()
,因为可以在索引中满足查询要求。
寻找指数成本
建立和维护索引结构可能会很昂贵,并且会消耗磁盘空间,CPU和I / O容量等资源。设计人员必须确保任何索引的好处都超过索引维护的负面影响。
使用这个简单的估算指南索引维护成本:每个索引维护通过INSERT
,DELETE
或UPDATE
索引键大约需要三倍的资源作为餐桌上的实际的DML操作。因此,如果您INSERT
将数据插入具有三个索引的表中,则插入速度大约比INSERT
没有索引的表中的插入慢10倍。对于DML,尤其是对于INSERT
繁重的应用程序,应认真审查索引设计,这可能需要在查询和INSERT
性能之间进行折衷。
也可以看看:
《 Oracle数据库管理员指南》以了解如何监视索引使用情况
索引内的序列化
使用序列或时间戳来生成自己索引的键值可能会导致数据库热点问题,从而影响响应时间和吞吐量。这通常是单调增长的键导致索引正确增长的结果。为避免此问题,请尝试生成在整个索引范围内插入的键,以使工作负载更具可伸缩性。您可以使用以下任何一种方法来实现:
-
使用反向键索引
-
使用哈希分区索引
-
使用循环序列为序列值添加前缀
-
使用可伸缩序列
也可以看看:
《 Oracle数据库管理员指南》中有关可伸缩序列的更多信息
SQL执行效率
在任何系统开发的设计和体系结构阶段,应注意确保应用程序开发人员了解SQL执行效率。为了实现此目标,开发环境必须支持以下特征:
-
良好的数据库连接管理
连接到数据库是一项昂贵的操作,高度不可扩展。因此,应尽可能减少与数据库的并发连接数。用户在应用程序初始化时进行连接的简单系统是理想的。但是,在基于Web的或多层的应用程序中,使用应用程序服务器将数据库连接复用到用户,这可能很困难。对于这些类型的应用程序,设计工作应确保池化数据库连接,并且不会针对每个用户请求重新建立数据库连接。
-
良好的光标使用和管理
维护用户连接对于最小化系统上的解析活动同样重要。解析是解释SQL语句并为其创建执行计划的过程。此过程分为多个阶段,包括语法检查,安全检查,执行计划生成以及将共享结构加载到共享池中。有两种类型的解析操作:
-
第一次提交SQL语句,但在共享池中找不到匹配项。硬解析是最耗费资源且不可扩展的,因为硬解析执行了解析中涉及的所有操作。
-
一个SQL语句提交给第一次,比赛被发现在共享池中。匹配可以是另一个用户先前执行的结果。SQL语句是共享的,这对性能有好处。但是,软解析不是理想的,因为它们仍然需要语法和安全性检查,这会消耗系统资源。
由于应尽可能减少解析,因此应用程序开发人员应设计其应用程序以解析SQL语句一次并执行多次。这是通过游标完成的。有经验的SQL程序员应该熟悉打开和重新执行游标的概念。
应用程序开发人员还必须确保在共享池中共享SQL语句。为了实现此目标,请使用绑定变量来表示查询在执行之间变化的部分。如果不这样做,则该SQL语句很可能仅被解析一次,而不会被其他用户重复使用。为确保共享SQL,请使用绑定变量,并且不要在SQL语句中使用字符串文字。
-
实施应用程序
开发环境和编程语言的选择很大程度上取决于开发团队中可用的技能以及在指定应用程序时所做出的体系结构决策。但是,有一些简单的性能管理规则可以导致可伸缩的高性能应用程序。
-
选择适合软件组件的开发环境,不要让它限制您的设计以决定性能。如果是这样,则您可能选择了错误的语言或环境。
-
编程模型可以在HTML生成和直接调用窗口系统之间变化。开发方法应专注于用户界面代码的响应时间。如果通过网络发送HTML或Java,请尝试最小化网络量和交互。
-
解释性语言(例如Java和PL / SQL)是对业务逻辑进行编码的理想选择。它们是完全可移植的,这使得升级逻辑相对容易。两种语言在语法上都很丰富,以允许易于阅读和解释的代码。如果业务逻辑需要复杂的数学函数,则可能需要编译的二进制语言。业务逻辑代码可以位于客户端计算机,应用程序服务器和数据库服务器上。但是,应用程序服务器是业务逻辑的最常见位置。
-
其中大多数不受编程语言的影响,但是掩盖数据库连接和光标管理的工具和第四代语言可能使用效率低下的机制。在评估这些工具和环境时,请检查它们的数据库连接模型以及它们对游标和绑定变量的使用。
-
数据管理与交易
其中大多数不受编程语言的影响。
-
-
在实现软件组件时,请实现其功能,而不要实现与其他组件关联的功能。实现另一个组件的功能会导致次优的设计和实现。这适用于所有组件。
-
不要在功能上留下空白,也不要在设计,实施或测试中对软件组件进行任何研究。在许多情况下,直到应用程序以实际量推出或测试后才发现差距。这通常表示体系结构不佳或初始系统规格不佳。在初始系统设计,构建和实施过程中,经常会忽略数据存档和清除模块。
-
在实现过程逻辑时,请以过程语言(例如C,Java或PL / SQL)实现。实施数据访问(查询)或数据更改(DML)时,请使用SQL。此规则特定于代码的业务逻辑模块,其中过程代码与数据访问(非过程SQL)代码混合在一起。将过程逻辑放入SQL访问存在很大的诱惑。这往往会导致占用大量资源的不良SQL。带有
DECODE
case语句的SQL语句通常是优化的候选对象,带有大量OR
谓词或set运算符(例如UNION
和)的语句也经常是优化对象MINUS
。 -
缓存经常访问的,很少更改的数据,这些数据重复获取的代价很高。但是,使此缓存机制易于使用,并确保它确实比访问原始方法中的数据便宜。这适用于所有模块,在这些模块中,应将经常使用的数据值缓存或本地存储,而不是从远程或昂贵的数据存储中反复检索。
本地缓存候选者的最常见示例包括:
-
今天的日期。
SELECT
SYSDATE
FROM
DUAL
可以占数据库工作量的60%以上。 -
当前的用户名。
-
重复的应用程序变量和常量,例如税率,折现率或位置信息。
-
本地缓存数据可以进一步扩展为在应用服务器中间层中构建本地数据缓存。这有助于减轻中央数据库服务器的负担。但是,在构造本地缓存时应格外小心,以免它们变得过于复杂而不会停止提高性能。
-
本地序列生成。
应该考虑使用缓存的设计含义。例如,如果用户在午夜连接并且缓存了日期,则该用户的日期值将变为无效。
-
-
优化组件之间的接口,并确保所有组件都在可扩展性最高的配置中使用。该规则需要最少的解释,并适用于所有模块及其接口。
-
使用外键引用。通过应用程序强制执行引用完整性非常昂贵。您可以通过从父级中选择子级的列值并确保其存在来维护外键引用。Oracle提供的不使用SQL的外键约束实施速度快,易于声明并且不会创建网络流量。
应用程序开发趋势
当今应用程序开发中的两个最大挑战是,越来越多地使用Java来代替已编译的C或C ++应用程序,以及越来越多地使用面向对象的技术,从而影响了模式设计。
Java为程序员提供了更好的代码可移植性和可用性。但是,与Java有关的性能有几个方面。因为Java是一种解释型语言,所以它执行类似逻辑的速度比诸如C之类的编译语言要慢。结果,客户端计算机的资源使用量增加了。这需要在客户端或中间层计算机中应用功能更强大的CPU,并需要程序员更加谨慎地产生高效的代码。
因为Java是一种面向对象的语言,所以它鼓励将数据访问隔离到不执行业务逻辑的类中。结果,程序员可能在不知道所使用的数据访问方法的效率的情况下调用方法。这往往导致最少的数据库访问,并使用最简单和最原始的数据库接口。
使用这种类型的软件设计,查询并不总是包含所有有效的WHERE
谓词,而是在Java程序中执行行过滤。这是非常低效的。另外,对于DML操作(尤其是对于INSERT
s),INSERT
将执行单个s,从而无法使用数组接口。在某些情况下,过程调用会使效率降低。与实际的数据库调用相比,将更多的资源用于将数据移入和移出数据库。
通常,最好将数据访问调用放在业务逻辑旁边,以实现最佳的总体事务设计。
在编程级别接受面向对象已导致在Oracle Server中创建面向对象的数据库。从在BLOB
s中存储对象结构到仅将数据库有效地用作索引卡文件,再到使用Oracle数据库对象关系功能,这已经以多种方式体现出来。
如果您采用面向对象的方法进行架构设计,请确保您不会失去关系存储模型的灵活性。在许多情况下,面向对象的方案设计方法最终会导致严重的非规范化数据结构,这需要大量维护和REF
与对象关联的指针。通常,这些设计代表了被关系存储方法取代的分层和网络数据库设计的后退。
总之,如果您将数据长期存储在数据库中,并且如果您期望在同一模式下进行一定程度的即席查询或应用程序开发,则关系存储方法可能会提供最佳性能和灵活性。
※ 如果您觉得文章写的还不错, 别忘了在文末给作者点个赞哦 ~
over