让Oracle跑得更快——Oracle 10g性能分析与优化思路(txt+pdf+epub+mobi电子书下载)


发布时间:2020-08-22 15:52:57

点击下载

作者:谭怀远

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

让Oracle跑得更快——Oracle 10g性能分析与优化思路

让Oracle跑得更快——Oracle 10g性能分析与优化思路试读:

前言

笔者在写这本书的时候,翻看了很多当前国内数据库方面的书籍,发现写性能优化的书并不多,特别是从工作经验和思路上来讨论性能方面的书,更是少之又少,这些因素让笔者思考要写这样一本书,这也算是这本书的一个定位。

在这本书里,你将会学到笔者在性能优化方面的一些思路和思考,一些故障处理的方法和原则,这些东西是笔者在实践中长期积累的心得体会,在笔者看来,掌握处理问题的方法和分析问题的思路在日常工作中显得更为重要,当你掌握了一些处理问题的基本思路之后,剩下的工作就是去Google或者阅读参考书了。

本书的一个特点是,凡是作者提到的观点,都尽可能地使用一些例子来证明它,这样看起来更有说服力一些。

为什么会出现数据库的性能问题

性能问题是最近几年来DBA们越来越关注的一个数据库技术领域,归根结底,造成它的原因是最近几年信息化进程的飞速发展,导致了很多系统的用户数量猛增,数据库中存储的数据量亦成几何级数激增,数据库作为数据处理和存储的最终受体,将必然直接承担这种变化导致的性能下降。因此在人们对信息的依赖性越来越强的时候,对信息使用的效率也变得越来越关注,这样数据库的性能优化问题就日益严重地压在DBA的身上。

什么时候需要对性能进行干预

itpub.net是国内最早的一个专业讨论Oracle数据库技术的论坛,目前在国内数据库方面已经相当有知名度,笔者是2001年注册的,算是最早的会员之一。目前仍然会经常上去看看,由于工作内容的关系,我比较关注性能方面的帖子,发现以下一类的帖子经常有很多,比如:

1.我是一个DBA,我现在手头有一个数据库,我该从哪里进行性能优化呢?

2.这是我的数据库的一个Statspack,我该如何优化?

通常对于第一个问题,我是很少回答的,并不是不屑于回答,实在是没有办法回答,如果我回答说,“你怎么知道你的数据库需要优化?”又担心这种没有实际意义的回答带有说教意味,打击别人的积极性,所以通常看看而已。实际上我是想说,对于一个DBA来讲,当你拿到一个数据库的时候,你首先需要做的是用最短的时间来了解一下跑在这个库上的是一个什么系统,比如是在线事务(OLTP)系统还是在线分析(OLAP)系统,这对于你做出性能上的判断至关重要,如果连系统都不了解,真不知道该如何去优化它,这就好比说,要设计一辆汽车,如果连用户对汽车的喜好都弄不清楚,如何能设计出一个取悦于用户的车呢?

对于第二个问题,像是比第一个具体一些,因为帖子作者已经提供了一个性能数据报告,但我仍然觉得通过这些数据没有办法准确地判断数据库是否有性能问题。比如你是一个医生,我让一个人站在你的面前测心率,结果是50次/分钟,你是不是可以断定他有问题,需要安装心脏起搏器呢?实际上是不需要,因为我知道他是一个运动员,这样的心率是正常的,而医生不知道,所以他在做出诊断之前需要详细了解站在自己面前的应诊者的所有详细信息,来作为他做出判断的依据。

下面贴出一个来自于我使用过的数据库性能报告中的一部分:

许多人看到这个数据一定会大声说:“嘿,你的数据库性能好差,buffer hit只有66%,不知道是谁设计的这个系统,赶紧加大data buffer的尺寸!”

诚然,这个数据的确显示数据库的内存命中率低得可怜,但是我想告诉你的是,这是一个在线分析(OLAP)系统的数据库,运行着很多非常大的查询,每个查询搜索的范围都在上亿条记录以上,那这个结果不是很正常吗?我们需要把几亿条数据缓存到内存里提供给这种每天可能只运行几次的查询吗?你可以同意,但是你的老板是不会同意的,这样做的成本太高了,而且完全没有必要,因为它只是一个报表系统,对数据库的响应时间要求不高,所以我们当然可以让这个查询直接到磁盘上去搜索数据,这也就是为什么在这样的系统里,buffer hit比例很低,但却是一个完全可以接受的值的原因。

笔者认为,只有数据库的性能已经影响到业务的正常工作或者用户已经无法满意于这种性能时,我们才应该考虑来优化它,对于绝大多数系统,数据库的安全和稳定才是最重要的。

FAST=TRUE?

这是很多人追求的目标,它的意思是,在Oracle数据库中,通过调整性能参数的值,就可以让数据库运转得飞快。

实际上这不过是句玩笑,它本身是一句反话,却让很多人误入歧途。我看到很多人,包括一些DBA,凡涉及性能优化,必定谈及性能参数的修改,这实在是一个误区,他把性能参数值的修改对数据库性能的正面影响人为地放大了很多倍,实际上恰恰相反,很多时候修改这些参数产生的却是副作用,原因很简单,Oracle给一个参数一个默认值是让它最大限度地适用于每个数据库,所以它几乎是最优的,当然,绝对有个别数据库需要适当调整,但我认为那是个例,并且,很多时候,修改这些参数的人,他们修改的理由并不是非常充分,不过是想修改一下看看运气而已。

本书的内容

以下是本书各个章节的内容简介。

第1章 引起数据库性能问题的因素

这一章主要讨论一些引起数据库性能问题的因素,包含了系统架构、软件代码、数据库设计、存储设计等话题。

第2章 锁和阻塞

在这一章里,将介绍Oracle数据库中锁的起因及由锁引起的性能问题—阻塞,并将讨论常见的几种阻塞的起因。

第3章 Latch和等待

这一章讨论Latch,它是Oracle中比锁更轻量级的一种串行机制。热块或是SQL未绑定变量是最常见的导致Latch等待的原因,这一章将对这些成因及解决方法进行论述。

第4章 优化器

优化器是SQL执行中最核心的部分,如果要分析SQL的性能,就不能不了解Oracle优化器的机制,这一章,我们就带你走进Oracle优化器—CBO的世界。

第5章 执行计划

当我们分析一条SQL语句的性能时,最先做的事情大概就是分析它的执行计划了。

所以,如果连执行计划都看不懂,那SQL调优根本无从谈起。在这一章,我们将讨论CBO(基于成本的优化器)执行计划相关的内容。

第6章 Hint

Hint指通过人为的方式来约束SQL的执行计划,让它按照我们希望的方式来执行,以达到我们需要的目的—改善性能或者仅仅是试验以对比SQL的执行性能。

这一章将讨论Oracle数据库中的大多数Hint。

第7章 分析及动态采样

对象采样分析是CBO(基于成本的优化器)的灵魂和核心,CBO如果没有了对象的分析数据,就好像一个医生不使用病人的病历来确定病人的病一样危险—那是一种没有依据的、盲目的行为。

在这一章里,我们将详细讨论Oracle中和对象分析相关的内容。

第8章 并行执行

这一章讨论一个和性能关系极大的技术—并行执行。

在OLAP(在线分析系统)或者是数据仓库系统中,并行技术使用得非常普遍,在合适的条件下,并行执行将会使SQL的执行效率大幅度提升。

第9章 变量绑定

这一章将详细讨论一个在性能优化领域经常被谈到的话题—变量绑定。

那么,是不是在任何时候变量绑定都是必需的呢?答案是否定的,在这一章中将给出答案。

第10章 SQL_TRACE和10046事件

SQL_TRACE和10046事件是会话级非常有用的两个工具,它们可以捕获会话当中SQL执行的详细信息,其中10046事件还可以获得SQL绑定变量的信息及发生的等待事件。

这一章将详细讨论这两个工具。

第11章 10053事件

这一章将详细讨论10053事件,它是一个很有用处的工具,当你发现一条SQL总是选择错误的执行计划,而你又百思不得其解的时候,也许你应该去生成一个10053事件的trace文件,看看CBO究竟是如何做出这样的执行计划的。

第12章 性能视图和性能参数

本章讨论一些Oracle数据库的性能视图和性能参数。

性能视图相对于SQL_TRACE来说,可以让我们更直接地获取一些性能数据,帮助我们判断数据库是否出现了性能问题。

而性能参数则让我们能够有机会选择一种最适合自己系统的某个参数值,以最大程度地满足当前系统的需要。

第13章 性能报告

本章介绍了常用的几个性能分析工具及性能报告,包括AWR,STATSPACK和ASH,其中以AWR性能报告作为重点介绍的对象。

本章以一个来自于现实生产数据库的AWR报告为题材,来讨论AWR报告的阅读方式,并最终判断出系统的性能所在;STATSPACK介绍了它的安装方法和如何生成报告;ASH也是以一个来自实际生产数据库的性能报告进行性能分析。

附录A 常见的等待事件

这部分会列出一些常见的等待事件、引起它们的原因及一些内部的机制,可以作为大家在处理性能问题时的一个参考部分。

后记 关于数据库的学习方法

这一部分是作者对如何学习Oracle的一个心得分享,对于Oracle初学者来说,正确的学习方法非常重要,它可以使你少走很多弯路。

如果初学者对于Oracle数据库的学习方法有兴趣,这部分可以作为本书的第一部分来阅读。

本书的读者对象

1.本书适合Oracle DBA或者和Oracle相关的开发人员。

2.本书的读者需要有一定的Oracle基础,比如你应该知道什么叫做表,什么叫做索引等。

约定

1.本书示例使用的Oracle版本是10gr2。

2.本书自创了一个术语—段对象。

这个词大家可能看着有那么一点陌生。作者的意思是,在Oracle数据库中,凡是分配了存储空间的,都称为段,所以段并不一定指的是表,也可能是表的一个分区,还可能是索引、大对象(LOB),或是IOT(索引表),物化视图等。在书中有时候需要描述这些对象时,单独说某个表,或者一个索引,都不能完全概括,所以就统称为段对象。

3.几个未作翻译的术语Extent,Latch和Bind peeking。

Extent:我看有些书翻译为“分区”,说实话,在Oracle里面,一提到分区,可能99%以上的人会认为是partition,还有的书翻译为“范围”,这个就更让人匪夷所思,所以在书中这个单词就没有翻译,相信大家也懂。

Latch:有的书翻译成“闩”,有的翻译成“锁存”,我总觉得还是不翻译好,只要大家知道它是Oracle里一种类似于锁的保证一些操作串行化的技术就好了。

Bind peeking:翻译成“变量窥视”或是“变量窥探”都非常不对头,所以干脆也不翻译。

本书的目的

笔者从事Oracle DBA的工作已经超过10年,对数据库的理解也一直在改变,就目前来看,我觉得最难的东西不是技术本身,而是什么时候该用什么技术。比如说要使用变量绑定,这非常容易,如果你不会,Google一下,差不多几分钟时间你就会了。可是,这个系统究竟该不该使用变量绑定,我想你Google一天或者一个星期也不一定有答案。原因是每个系统都是独立的,都有自己的业务特点,这需要技术人员根据自己系统的业务特点来度身定做符合自己系统的技术特性。

让读者在每一个技术面前先停下来思考一下,这个技术究竟在什么时候应该用,什么时候不应该用,这是笔者写本书的最终目的。

致谢

感谢www.itpub.net网站的创始人Tigerfish为本书写序,我一直对他怀有敬意,他在推动中国Oracle数据库的发展上功不可没。

感谢biti(冯春培),eygle(盖国强),kamus(张乐奕)和warehouse(谢永生),他们都是国内顶尖的Oracle专家,感谢他们为本书写的精彩点评。

还有来自ITG的Mike,感谢他的热心帮助和鼓励。

感谢ITPUB的王蓓小姐(贝贝),在本书的出版过程中,她做了大量的协调工作,才保证这本书的顺利出版。

感谢电子工业出版社的张月萍策划和高洪霞编辑,是她们的努力让本书更具可读性和完整性。

最后要感谢我的妻子tracy和儿子思墨,是他们让我一直努力工作,最终使本书得以问世。

第1章 引起数据库性能问题的因素

在我看来,一个数据库是否存在性能问题,基本上在系统设计的时候就决定了,这里说的系统设计包含软件的设计,数据库的设计和硬件的设计。软件的设计包含了软件系统架构的设计,软件代码的编写;数据库的设计包含了数据库的类型选择和根据数据库类型的所有数据库对象的设计;硬件的设计包括存储结构的设计,硬件的性能选择和冗余设计。在一个系统的设计阶段,其中任何一个环节存在设计不得当之处,都可能导致系统的性能下降,而系统的性能在多数情况下又反映为数据库的性能问题。

1.1 软件设计对数据库的影响

1.1.1 软件架构设计对数据库性能的影响

软件系统的架构对数据库的影响是非常直接的。例如一套系统,如果并发数非常大,比如是超过3000个并发,通常这种情况下,我们会考虑采用一套软件来搭建一个中间层,这就是通常讲到的3层或是多层结构。使用这一套软件的目的是用来构建一个缓冲池,在数据库之前对大量的并发进行处理,以便于每次只有少数的用户连接到数据库中,其他的用户在缓冲池的队列中等待。当然,这只是一个动态的过程,程序会尽可能快地去响应所有用户的请求,这种提前对大量并发用户进行处理的方式,会比让这3000个用户直接连接到数据库中效果要好得多,同时数据库也可以使用更多的资源来处理用户的操作请求而不是去开3000个进程来处理每个用户的请求,这个开销是非常大的。所以对于大量并发的系统来讲,在数据库之前建一个缓冲用户请求的中间件服务,显得至关重要。同时,很多这种中间件软件还提供了负载均衡的功能。

当然,Oracle数据库自身也提供了一种MTS的技术,作用和这种中间件服务是一样的,但目前看来,采用商业中间件软件或是开发商自己开发一套中间件服务的做法更多一些(参见图1-1)。图1-1 多层架构体系1.1.2 软件代码的编写对数据库性能的影响

软件代码对数据库的影响,通常指的是应用程序代码中对数据库操作的代码部分对数据库产生的影响。具体来讲就是SQL语句或是PL/SQL包。SQL语句造成的影响,一种是SQL语句本身在逻辑上就是效率低下的,另一种就是SQL语句没有绑定变量。

性能低下的SQL语句,比如使用Hint,不合适的外连接,谓词的隐含转换,优化器的选择等,会对SQL的执行产生非常大的影响,特别是多表关联的情况下,影响更是显著。它主要体现为SQL语句的执行受到了人为的约束,比如数据的访问方式(索引还是全表扫描),以及表关联方式的选择上(Hah Join,Nested Loops)。

1.1.2.1 人为地在SQL代码中加入Hint来约束SQL的执行计划

我曾经遇到的一个例子就是这样,开发人员为了要求每次对一个表做操作的时候都使用索引,于是在代码中强行加入了Hint约束SQL的执行计划,它的样子大概是这样:

我猜测他们在系统上线之前测试的阶段,发现这条SQL选择索引比全表扫描效率高得多,为了保证以后执行计划能够始终选择索引,他们在代码中的SQL里加入了这个Hint。

系统上线后,没有出现过问题,直到有一天用户抱怨查询非常慢,我从数据库里得到了用户端发出的SQL,才知道这个SQL在代码里加入了Hint。问题是,为什么之前操作都没有问题呢?我登录这个数据库,查看了一下这个表的信息,惊奇地发现,这个表每天仍然定时在做分析操作,这是一个奇怪的现象,人为地对表进行定时分析,却不允许数据库来选择执行计划,这显然是不合理的事情。但这种现象在开发人员当中又是比较普遍的,大家了解一些数据库的技术,却无法将这些知识整合起来运用,系统设计及开发阶段,没有DBA参与进来,直到系统进入运行维护阶段,才有DBA来充当救火队员的角色,这在当前中国软件开发中是一个很普遍的现象。

接着说这个案例。这是一个Oracle 10gr2的数据库,CBO(基于成本的优化器)的技术已经比较成熟,所以此时应该选择由Oracle数据库来决定SQL的执行计划。我分别执行了这条原始SQL和去掉了Hint的SQL,并获得了各自的执行计划,执行计划显示出,去掉Hint的SQL选择了全表扫描(Full Table Scan),执行中扫过的数据块远远小于通过索引访问数据的SQL,于是原因找到了。

可是为什么之前没有出现过这个问题?我对比了一下最近的数据和之前的数据,发现近期的数据在创建索引的列上的列值重复率要远远高于从前,因此Oracle在选择索引之后,比以前读取了更多的索引块和数据块,造成了大量的I/O操作。

因此,对于高版本的数据库(10g以上),我们还是应该让数据库自己根据表、索引的统计分析信息来决定SQL的执行计划,因为表中的数据是会变化的,这种人为的强行干预,必然会在某个时候出现问题。

1.1.2.2 不必要的外连接操作

外连接是一个代价非常昂贵的执行过程。如果业务需要,这种操作是必要的,但是有时候会出现人为地在SQL中使用不必要的外连接的情形,这实际上是因为有的开发人员担心遗漏一些数据而刻意使用它,这就非常有可能留下隐患,让数据库选择昂贵的执行计划而不是最优的那一个。

下面的这个例子说明了一个不必要的外连接使用。

我们创建两个简单的表,并插入一些数据,同时给其中的一个表T2的C列上插入一些空值:

通过下面这条语句,通过使用A字段和T2表C字段关联,我们获取了T1表上所有的行,以及T2表上符合条件的行:

请看下面这条SQL,它是什么意思呢?

这条SQL的意思是告诉数据库,我要得到T1表上所有的行,并且用A列和T2表C做关联,同时要求T2表C列的值大于1000。

让我们再看看另一条结果集完全一样的SQL:

从结果集上来看,这是两条等价的SQL语句,就是说,在这种情况下,外连接其实是没有用的,是人为地在SQL里设定的限制!如果仔细看一下第一条语句,我们不难发现,条件中T2.C>1000已经明确地指出,在结果集中,T2表在任何一行,C列都应该有值的,也就是在这种情况下,根本就不需要使用外连接,业务逻辑上讲,外连接在这里是多余的。这种情况在开发人员的代码中有时候会遇到,对他们来讲,只要保证结果集正确就好,但对数据库来讲,在执行时可能会引起极大的性能差别。

1.1.2.3 CBO下优化器模式的选择

通常对于一种功能单一的数据库来讲,在实例级设置一个优化器模式就可以了,比如对于OLAP系统,绝大多数时候数据库上运行着的是报表作业,执行基本上是聚合类的SQL操作,比如GROUP BY,这时候,把优化器模式设置成all_rows是恰当的。

而对于一些分页操作比较多的网站类数据库,设置成first_rows会更好一些。

我却遇到了另外的一件事情。我们的数据库上运行着的基本上是一个OLAP系统,所以优化器模式设置为ALL_ROWS,这有利于报表SQL的快速完成。但数据库上还运行着一些用户查询的业务,查询的方式可以说成是分页的。有时候就会出现用户抱怨查询慢的问题,尽管我知道问题所在,却比较难解决,因为这些SQL已经被开发人员写到代码里面了。

针对这种情况,如果能在开发阶段就考虑到这个问题,针对需要分页操作的SQL,开发人员在SQL里通过Hint的方式来将优化模式转换成FIRST_ROWS,这样就可以大大地提高数据的处理速度。

比如这样一个每次取出10条记录的分页查询:

可以在每个子查询中重复使用FIRST_ROWS(n)来提高查询效率。

尽管说在SQL中人为地加入Hint操作不是一个好主意,但是有些时候,比如需要兼顾其他的用户操作时,可以考虑做这样的设定。但前期需要做一些测试工作,以确保这样的设定能够带来性能上的提高,同时不会对数据库造成其他方面的影响。这是系统设计阶段应该仔细考虑好的一个问题。

1.1.2.4 没有绑定变量的SQL

对于这个话题,其实很多人存在着一个误区。记得有一次在广州出差,我和一个同样做数据库的同事,有这样一段对话:

同事:“我们的系统有没有绑定变量?”

我:“不知道.....”

同事:“我发现没有绑定。”

他的表情很凝重,仿佛发现了数据库的一个致命隐患一般。

我:“无所谓吧?”

他立即反驳我说:“谁说无所谓,SQL没有绑定变量,数据库每次执行就会发生硬分析(Hard parse,喜欢读Statspack Report的朋友对这个词应该很敏感吧,我的同事就是一个Statspack fans,那时候他正在研究Statspack,觉得如果硬分析太多了,天就要塌下来,仿佛把这些硬分析变为软分析之后,数据库性能会提高成百上千倍一样),这样性能肯定会大受影响,有时候用户反映查询慢,会不会是这个原因导致的?”

我说不是这个原因导致的,我可以保证,因为我们是这样的一个系统:数据库的用户连接数很少,大概不会超过50个,每个用户每天发出的查询操作不会超过50个,这对于一个运行在内存8个GB,10几个CPU的系统上的数据库来说,硬分析对数据库性能的影响微乎其微,完全可以忽略掉,因为我们是一个OLAP系统。

他想了一下,认同了我的观点。

我想说的绑定变量的误区就和上面这个案例一样,有时候它对性能的影响被夸大化了。我在ITPUB上总看到很多这样的帖子,大家在谈及SQL时必定要求绑定变量,仿佛不这样系统就要出问题了一样。实际上,至少对于OLAP系统(在线分析系统,通常指的是这样的一个系统,数据库存放着海量的数据,连接的用户少,SQL语句基本上都是用户产生报表的大查询)来说,未绑定变量对数据库的影响是很有限的,甚至是完全没有必要的,因为只有少量的用户和少量的SQL操作,数据库不需要花多少资源在SQL分析上面。这个话题我们会在后续的章节中讨论到。

绑定变量的真正用途是在一个OLTP系统中,这个系统通常有这样的特点,用户并发数很大,用户的请求十分密集,并且这些请求的SQL大多数是可以重复使用的,我们试想,当这些成千上万的SQL被数据库一遍又一遍地进行语法分析、语义分析,生成执行计划时,这对数据库的压力该有多大?如果一条SQL执行一遍之后就被缓存到数据库的内存当中(实际上是在共享池里),以后的成百上千的用户请求都使用这个SQL解析后的结果,那效率将有多么大的提高!

所以,我的观点是,当你要考察绑定变量对你的数据库的影响有多大时,先确定你的系统是OLTP系统或是OLAP系统;当然,现在很多数据库同时担负这两种角色,那么你需要分析数据库的性能情况,比如,做一个Statspack Report来帮助你确定变量是否绑定,以及是否已经对系统的性能构成严重的影响。

1.1.2.5 PL/SQL包

如果你的程序里面有PL/SQL包,请考虑使用存储过程来代替它,存储过程是经过成功编译后存放在数据库中的代码,执行起来的效率要比程序代码中PL/SQL包的效率高很多,因为它不再需要做语法和语义的分析(语法的分析指的是数据库对代码进行检查,看它是否存在语法上的错误;而语义分析是查看语句执行的对象是否存在,比如需要操作的表、列等,以及是否有执行这些操作的权限)。

1.2 数据库的设计

数据库的设计在系统设计当中是一个非常重要的环节,但目前看来,很多开发商忽略了它应有的重要性,大多数的数据库设计基本上等同于创建业务所需要的所有对象,仅此而已。这是作者从事了10年DBA工作的切身体会,也许这也不能全怪开发商,比如他们有工期的压力,有人员成本的压力,那应该是另外一个话题。

对于数据库的设计,我认为除了一些必需的对象创建之外,应该还要更多地考虑在整个系统运行的生命周期中,按照系统的实际情况及可能的变化做一些前瞻性的设计,以基本满足系统生命周期里的各方面需求,不至于发生大的修改或是升级。

说起系统的升级,这是一个有趣的话题,可能很多开发人员,特别是做项目开发的人员,应该会深有体会。比如我身边的一些案例,明明是最初设计上存在着缺陷或者疏漏,导致后来系统出了问题,却成了开发商项目的二期、三期的理由,也成为软件1.0版、2.0版的理由。

基本上看来,前期数据库设计的一个根基就是要弄清楚数据库的类型。通常来说,我们把业务分为两类,在线事务处理系统(OLTP)和在线分析系统(OLAP)或者DSS(决策支持系统),这两类系统在数据库的设计上是如此不同,甚至有些地方的设计是貌似相悖的。比如OLTP系统强调数据库的内存效率,强调内存各种指标的命中率,强调绑定变量,强调并发操作;而OLAP系统则强调数据分析,强调SQL执行时长,强调磁盘I/O,强调分区等。因为这些区别,在数据库设计的阶段,弄清楚数据库类型是至关重要的,只有在这个前提之下,才能够讨论数据库的具体设计,否则设计必然是盲目的,“皮之不存毛将焉附”。1.2.1 OLTP数据库

OLAP和OLTP是两类完全不同的系统,对数据库的要求也截然不同。通常来讲,OLTP(在线事务处理系统)的用户并发数都很多,但他们只对数据库做很小的操作,数据库侧重于对用户操作的快速响应,这是对数据库最重要的性能要求。我清楚地记得在2008年的时候,某个门票在线销售系统允许人们通过网络购买门票,这是一个典型的OLTP系统。我当时还想尝试去买一张,结果是还没等到我去买,就听说系统瘫痪了。我想,应该是在线购票的用户数太多吧,导致数据库(我不太确定,也可能是中间件系统)没有办法处理大量的连接,从而导致了系统崩溃。这真是一个惨痛的教训,它用事实告诉我们,对于一个系统,特别是非常重要的系统,一些前瞻性的预测和系统的压力测试有多么的重要。

对于一个OLTP系统来说,数据库内存设计显得很重要,如果数据都可以在内存中处理,那么数据库的性能无疑会提高很多。我知道有些对处理速度要求很高的系统,已经采用了一些内存数据库,比如Oracle的Times Ten。

内存的设计通常是通过调整Oracle和内存相关的初始化参数来实现的,比较重要的几个是内存相关的参数,包括SGA的大小(Data Buffer,Shared Pool)、PGA大小(排序区,Hash区等)等,这些参数在一个OLTP系统里显得至关重要,OLTP系统是一个数据块变化非常频繁、SQL语句提交非常频繁的系统。对于数据块来说,应尽可能让数据块保存在内存当中,对于SQL来说,尽可能使用变量绑定技术来达到SQL的重用,减少物理I/O和重复的SQL解析,能极大地改善数据库的性能。

关于一些初始化参数的设定的问题,我认为,这里绝没有一个确定的标准,这和每个数据库上运行的业务直接相关,能够确定这些参数值的唯一方法就是测试,先给这些参数设定一个经验值,然后通过搭建测试环境对数据库进行测试,通过一些性能报告(比如AWR或者Staspack 报告)作为依据,不断地调整这些参数值,以达到最佳的性能。

除了内存、没有绑定变量的SQL会对OLTP数据库造成极大的性能影响之外,还有一些因素也会导致数据库的性能下降,比如热块(hot block)的问题,当一个块被多个用户同时读取的时候,Oracle为了维护数据的一致性,需要使用一种称为Latch的东西来串行化用户的操作。当一个用户获得了这个Latch后,其他的用户就只能被迫等待。获取这个数据块的用户越多,等待就越明显,就造成了这种热块问题。这种热块可能是数据块,也可能是回滚段块。对于数据块来讲,通常是数据块上的数据分布不均匀导致,如果是索引的数据块,可以考虑创建反向索引来达到重新分布数据的目的,对于回滚段数据块,可以适当多增加几个回滚段来避免这种争用(热块部分在后面有专门的章节讨论)。1.2.2 OLAP数据库

我一直认为OLAP数据库在内存上可优化的余地很小,甚至觉得增加CPU处理速度和磁盘I/O速度是最直接的提高数据库性能的方式,但这将意味着系统成本的增加。实际上,用户对OLAP系统性能的期望远远没有对OLTP性能的期望那么高。

内存的优化,对OLAP来讲影响很小,比如我曾经遇到的一个数据库,每天晚上运行的报表程序,基本上都是对几亿条或者几十亿条数据进行聚合处理,这种海量的数据,全部在内存中操作是很难的,同时也完全没有必要,因为这些数据块很少重用,缓存起来没有实际意义,倒是物理I/O相当大,这种系统的瓶颈往往是在磁盘I/O上面。

对于OLAP系统,SQL的优化显得非常重要,试想,如果一张表中只有几千条数据,无论执行全表扫描或是使用索引,对我们来说差异都很小,几乎感觉不出来,但是当数据量提升到几亿或者几十亿甚至更多的时候,全表扫描、索引可能导致极大的性能差异,因此SQL的优化显得重要起来。

看下面的一个例子,它对比了索引和全表扫描的效率:

我们看到,在这个只有几万条记录的表中,相同的SQL语句,全表扫描扫过的数据块(一致性读)是695个,而索引只扫过了17个,差别还是非常大的。

分区技术在OLAP数据库中很重要,这种重要主要体现在数据管理上,比如数据加载,可以通过分区交换的方式实现,备份可以通过备份分区表空间实现,删除数据可以通过分区进行删除;至于分区在性能上的影响,不能一概而论,认为分区的性能将始终好于非分区,这个结论是不成立的,至少是片面的,我们通过以下几种情况来分析它。

1.当查询的范围正好落在某个分区的时候

这时候分区的效率自然是高于没有分区的,因为SQL在有分区的表上只扫过一个分区的数据,而对于没有分区,需要扫描整个表,这也是大多数人认为分区会提高性能的一个原因吧,比如下面的例子:

第一个SQL只扫过了一个分区的数据,扫过的数据块为23个;第二个SQL做了全表扫描,扫过的数据块为84个,这种情况下肯定是分区表的效率要高一些。

2.当查询的范围跨越几个分区时

这时候分区可能并不绝对是最优的,比如下面的例子,我们把查询的范围扩大到分区表的13个分区,让CBO使用FAST INDEX FULL SCAN的方式扫描索引,另外我们创建另一张非分区表,表结果和数据同分区表完全一样,我们使用同一条SQL,并且也让CBO强制使用FAST INDEX FULL SCAN的方式访问非分区表上的全局索引。我们要验证的一个观点是,分区索引并不一定比全局索引在任何时候都快,有时候它反而会慢。下面是输入的结果:

在这个例子里面,分区索引之所以扫过了更多的数据块,是因为分区索引在做FFS(INDEX FAST FULL SCAN)的时候只能够在本地索引上进行,如果涉及其他的分区,还需要按照访问索引的方式去访问其他索引(比如先找到其他分区索引的根数据块,再找到最左边的叶块,然后执行FFS操作),这样,查询跨过的分区越多,这种额外的代价就越大;而在这种情况下,全局索引只需要定位到一个叶块,然后执行一次FFS就能够扫过所有的索引叶块,这样性能就会好于分区索引。

上面的例子是想说明,OLAP环境中,分区主要的功能是管理上的方便性,它并不能绝对保证查询性能的提高,有时候分区会带来性能上的提高,有时候甚至会降低,就像我们在例子中看到的一样。

1.3 数据库的硬件设计

数据库的硬件设计在性能上主要体现在:

● CPU

● I/O

● 负载情况

这些指标需要对业务进行综合评估和系统测试之后,做出一个合理的硬件配置清单。

数据库的硬件设计包含了数据库服务器的架构和数据存储。这些因素在数据库设计阶段将作为重点的考虑因素。如果当系统上线之后,出现冗余或者空间不足的问题,将是一件非常麻烦的事情。

数据的存储和安全应该主要考虑以下几个问题。1.3.1 存储容量

如果一个系统的生命周期可以确定,或者说数据库中的数据保存时间可以确定,那么我们就可以通过一个简单的计算,大致估算出数据库所存放的数据量的大小,以作为存储设备采购的一个依据。

可以通过估算占有存储空间的所有数据库对象(其实主要是估算业务用户下的所有对象)的容量,来计算数据的容量。

占用空间的对象都可以在DBA_SEGMENTS视图里面找到,数据库的空间的分配是以段的形式分配的,凡是段对象,都是要占用空间的,它包括表、索引、物化视图、其他的一些大对象(比如全文索引对象)。

如果在开发阶段能够预测每个表的记录数,然后我们取得这个表的字段总长度,于是表的容量=记录数*字段长度。

一个表中索引的大小和索引的类型,以及索引键值的重复率有很大的关系,开发人员可以通过模拟一些实际数据来估算出索引和表数据的一个比例,然后做出索引所占空间的估算。

一个计算容量的例子如下。

我们创建一个表,然后在表上创建索引,之后对表和索引进行分析,然后查询视图user_tables就可以得到表的大致容量。

这个数值就是表的平均行长,如果我们能够估算出预期表的记录数N,那么最终表占用的空间就是 93 bytes*N:

我们取得了测试表中表和索引的大小,计算出索引和表大小的百分比,这样,我们就获得了最终这个表的空间使用量为:

这就是预期这个表的容量,如果能够预测出未来数据库的数据量,我们就可以比较客观地估算出数据库预期的容量大小。

另外一个容易被开发商忽略的问题是对系统备份数据占用空间的考虑。我遇到的一些系统就有这个问题,系统上线之后才发现,设计人员根本就没有考虑过系统备份的问题,也没有预留出足够的空间来做数据备份,给DBA带来的压力相当大。为了保证数据的安全,我设计了一套备份方案,由于磁盘的空间有限,在备份新的数据的同时,还需要及时删除一些旧的备份数据,在这种磁盘空间捉襟见肘的空隙下工作,DBA有时候觉都不能睡安稳。1.3.2 存储的物理设计

现在越来越多的大数据量数据库选择了SAN存储结构(参见图1-2),这是一个扩展性非常好的存储设计,它可以非常方便地将存储设备增加到存储网络当中,但成本和故障点相应地就会变多,对维护人员的技术要求就很高,它不但要求维护人员懂得磁盘阵列的技术,还要掌握SAN交换机的相关技术。图1-2 SAN存储架构1.3.3 数据的安全

数据的安全是系统设计阶段应该充分考虑好的一个问题,要按照用户对数据安全级别要求的高低,以及运行业务停止的时长来设计数据库的安全解决方案。

大致来讲,用户对数据安全的要求有如下几个层次。

1.3.3.1 Data Guard结构

如果用户对数据的安全性要求非常高,并且对系统的宕机时间要求很高,可以考虑Data Guard设计结构(参见图1-3),当主数据库出现故障时,维护人员可以用最短的时间启用备用数据库,保证业务的正常进行。

1.3.3.2 RAC结构

RAC结构(参见图1-4)和Data Guard结构分属于不同级别的安全设计,Data Guard能够保证数据不丢失或者尽可能少丢失(注:Data Guard有三种保护模式,具体细节请参考Oracle官方文档),它是数据库级别的一个冗余结构。而RAC则是实例级的一个冗余结构,它能够保证数据库在一个实例出现故障之后,用户操作可以无缝地由另外一个实例接管,现在很多对业务连续性要求很高的系统都采用了RAC+Data Guard的数据库结构设计。图1-3 Data Guard结构图1-4 RAC结构

1.3.3.3 Rman+归档的方式

Rman+归档的备份方式相对RAC+Data Guard来看,它的优势在于成本上要廉价,并且能够保证数据的完整,当数据库损坏时,如果我们保留有完整的备份集和归档日志,就可以将数据库恢复到最后出现故障时的时间点。缺点是需要较长的宕机时间。

1.3.3.4 数据导出方式(exp/imp,exdp/imdp)

这两种数据导入导出方式更像是一种数据传递或者数据保存,它不能保证数据的安全。

1.4 小结

1.系统的数据库类型,OLAP还是OLTP

弄清楚系统是OLAP或是OLTP是一件非常重要的事情,它将影响到数据库所有的相关设置,不论是内存参数、存储参数还是性能参数,可以说是系统设计阶段数据库设计最优先考虑的事情。

2.系统并发量

如果是一个OLTP系统,并发将作为非常重要的一个因素考虑,如果设计阶段没有对系统预期的并发数做出准确的估算,将会出现非常严重的后果,比如前面说的那个门票销售系统的例子。

高的并发数可能导致这样两个严重的后果:

● 系统资源严重被使用,系统过负荷运行。

● 严重的等待事件,比如前面讲到的热块以及锁定等情况。

3.SQL代码的编写

性能低劣的SQL对数据库的杀伤力是巨大的。开发人员,特别是数据库接口的开发人员,应该好好学习一下SQL的开发技巧,它不但包括SQL功能的实现,还有SQL语句的优化性。可是很遗憾的是,很多开发人员忽略了SQL的开发技巧。

4.数据库的设计

数据库本身的设计在系统设计中也是至关重要的,因此我更推崇让DBA来参与或者执行这个工作,因为DBA会更关注数据库自身的问题,会让数据库变得更可用。

5.存储的设计

在系统设计阶段,一定要预测系统预期的数据使用空间,否则以后数据库扩容将是一件非常麻烦的事情,特别是那些不允许宕机的系统,尤其应该将各种因素考虑清楚,最大可能地消除将来由于系统自身设计的问题导致的隐患。

第2章 锁和阻塞

2.1 关于锁

锁这种东西,对于初学者来说就像是一个深不可测、遥不可及的概念。我的经验告诉我,如果初学者冲上来就去纠结Oracle各种锁的概念、锁的类型、锁的级别,试图用最快的方式来理解锁的含义,基本上都会感到痛不欲生,至少我当时的心情大致如此。

随着工作时间的变长,我慢慢地养成了一种和从前不太一样的思维方式。比如现在我们在谈锁,以前的方法是,首先会去找文档来看什么是锁,费力不说,到底也没有搞清楚;而现在的思维方式转变了,开始学会用一种轻松、主动的方式来思考问题,于是我首先会去想,为什么会有锁?没有它会怎么样?

我必须要向大家推荐后面一种思考方式的好处。这是一种启发式的思考模式,是主动的,所以它是快乐的。而前一种是消极的,被动的,同时也是痛苦的。我就曾经在这样的痛苦中摸索了很久,希望大家不要重蹈我的覆辙。

为了说明这样的一种思维方式,我举一个例子,想必大家都切身感受过。

中学时候学万有引力定律时,老师上来就告诉我们,世间万物是相吸的,并由牛顿发现了它,下面是万有引力定律的公式……于是大家机械地听着,记着,背着。坦白地说,这样被动接受的感觉很一般,但至少还不太痛苦,因为我们还能听懂。大家试想一下,万有引力是多么美好的东西啊?如果我们托着下巴,呆呆地坐在窗户前面想,为什么地球就要绕着太阳转呢?为什么不会飞走呢?如果有一天飞走了,我们怎么办呢?这看起来是在胡思乱想,比起课堂老师上来就捞干的说要低效得多,但是往往就是在这种低效中,我们获得了任何人都不能给予的东西,我们通过自己的思维推理,得出了这个结论:太阳对地球是有吸引力的。这是我们主动获得的东西,我们充满了成就感和自豪感。

前面扯了一些看似不着边际的话,在我看来非常重要,这也是我想通过这本书想表达的另一个目的,就是学会思考。它比我直接告诉你锁是什么要重要得多,它希望你能够像思考地球为什么围绕着太阳转一样,托着下巴来思考Oracle数据库为什么会发明一个锁,这不是扯淡。

让我们一起来思考这个问题吧,如果你还不太习惯这种思考方式的话。为什么Oracle数据库中会有锁呢?设想,如果世界上只有你一个人,你有一箱子金币,你会弄把锁头来把它锁起来吗?不会,因为如果世界上只有你一个人,根本就不会有锁头这种东西出现,因为没有其他高等生物会去打开它,除了你。你可能会问,举一个如此粗鄙的例子给我们描述锁,太不把Oracle放在眼里了吧?其实不是这样的。Oracle的锁和这个锁头一样吗?答案是一样的,就是因为受现实生活中的锁头的启发才取了这个名字(lock),所以你看,它神秘吗?一点都不神秘,那不过是一层窗户纸,只需要我们的轻轻一捅。

继续我们的推理,现实生活中因为存在着其他想得到箱子里金币的人,你为了防止他们来拿,所以上了锁。在数据库中也存在着类似的事情,如果一个数据库只有你一个人用,我绝对不相信Oracle会费这么大的劲开发出一个锁来捣乱,所以,我们的答案找到了,因为还有其他的人在使用这个数据,你为了防止他们把你做的事情弄糟,所以在你对数据操作的时候,拒绝他们操作!简单吧?是不是还有点高兴?我们就在说说笑笑的过程中了解了锁的渊源。

可能有人跳出来说,你说了半天只是说了一个锁,锁分很多种啊,表级锁、行级锁、共享锁、排他锁……你再来用你的快乐法推啊!

那好,我们再推,我们这回从哲学上来推。哲学真是一个非常高深莫测的学科,我一直觉得只有一些绝顶聪明的人才能学懂哲学,我是学不懂的,只能引用他们发明的一些话。比如现在我引用这条“存在即合理”。就是说,Oracle的老板不是笨蛋,没必要花高昂的费用雇人写一些没有意义的代码。那么,对于一个公司来说什么叫有意义?能满足用户的需求即为有意义,好了,答案找到了,用户A的系统需要用到表级锁,Oracle公司为了把数据库卖给他,所以开发了表级锁,用户B需要用到行级锁,所以Oracle为他们开发了行级锁……

做技术的人,总想把所有的技术都学会,之前我也曾这么学过,后来发现学完之后很快就忘了。比如最开始Oracle推出RAC的时候,我们费尽千辛万苦搭好了一个环境,开始很激动,整天在上面打命令。可是没持续多久,就没人用了,原因是大家不知道该做什么了,该做的都做完了。看起来是该会的都会了,其实是什么都还不会,比如说RAC对系统的影响究竟有多大?什么样的系统需要用RAC?RAC在资源分配上需要怎样的配置才合理?一堆的疑问摆在我的面前,我发现我什么都没学会,因为我没有认真思考Oracle为什么会发明一个RAC。

一年后,每个人几乎把所做的测试统统忘光了,直到我们的系统中真正用到了RAC,才开始有目的地研究起来,那时候故障不断,一个月的时间锻炼要强过以前好几个月的自学。

说这个例子是什么意思呢?就是要说,很多概念或者技术,看起来很深奥,那是因为你没有用到,当你用到的时候,你会觉得它无非是满足用户需求的一个产品,仅此而已。上面讨论的锁也一样,它对于你很陌生,说明你现在没有用到它,还不需要它,当你需要它的时候,你会发现它正好能满足你的需求,那时候不要说理解,基本上就是拿来就可以用了。很多人学了无数年的经济,却比不上一个几乎没有读过书的人懂得做生意,因为前者在漫无目的地机械地学,后者在为了生存下去而不断地思考。这就是区别。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载