1.此书荣获2006年度业界最高荣誉奖项——Oracle杂志编辑选择奖;
2.世界级Oracle大师Jonathan Lewis的最新力作;..
3.该书以专家的视角对Oracle系统的基于成本的优化模型进行了深入浅出的分析和介绍;
4.近几年来Oracle领域最重要的著作之一,受到无数读者、网友和专家的好评。...
★数据库领域的超级畅销书,世界级Oracle大师Jonathan Lewis的最新力作!
★荣获2006年年度Oracle杂志编辑选择大奖!
★受到无数读者、网友和专家的好评,被翻译成多种语言,成为众多中高级Oracle用户、DBA和开发人员的必看图书!
对于基于成本的优化器的执行方式,Jonathan有着深刻的见解,本书能够帮助DBA成为更好的设计者,还能帮助开发人员开发出更卓越的代码。
——Thomas Kyte Oracle公司全球副总裁
基于成本的优化是数据库根据统计以预测的方式选择一种可能最快的执行方式。对执行性能高度敏感的应用使用CBO可以成倍加速SQL的执行速度。本书的日的在于解释优化器执行计算过程中的主要特性,以此分析计算成本,并确定SQL语句的执行计划,作者还深入剖析了优化器产生的成本与实际资源消耗之问的关系。
相信Jonathan Lewis对CB0精湛的阐述将使得Oracle DBA能够更好地管理数据库的执行,开发人员将能够更好地开发数据库应用程序。
——罗铁庚 国防科技大学计算机学院教授
这是一本非常优秀的介绍Oracle系统的技术图书,该书以专家的视角对Oracle系统的基于成本的优化模型进行了深入浅出的分析和介绍。另外,这本书的内容组织和案例选用也别
具匠心,引人人胜。
——闪四清 著名数据库专家
亲爱的读者:
在Oracle帮助论坛上我们经常会看到类似“为什么Oracle在有索引的情况下没有使用索引?”的问题。明明已经明确选择了索引列,排序也正常,也做了统计,空列也已经选出米了,但优化器就是没有自动使用索引。到底是什么地方出了问题?
如果本应该以最优的执行方式,而且也花费了非常多的时间想要优化器能够按照自己的方式来进行优化,但是优化器的执行却完全不是那么回事,那么我建议您读读这本书。学习完本书后,您将能够理解优化器的“思维”、知道错误是如何造成的以及导致错误的数据模式,从而可以节约在设计和SQL查错方面耗费的大量时间。
基于成本的优化器是包含了Oracle数据库工作模式的一组代码。在数据统计上运用这一模式,优化器将以最有效的方法将查询变换为有效的执行计划。遗憾的是,模式_并非总是完美无缺,统计也并不一定完美,从而导致执行的结果并不理恕。
任《基于成本的Oracle优化法则》一书中(本系列三本中的第一本),我们讨论了最通用的模式,优化器如何基于统计信息进行优化,以及为什么有时候优化的结果不尽如人意。这样,通过调整模式或创建出更切合实际的统计信息,您就可以纵览整个问题而不必拘泥于单个SQL语句。
我们日常生活的很多方面都离不开数据库的支持,从银行业务、电话缴费乃至小型家庭账本系统都能看到数据库的影子。近年来,数据库技术的发展非常迅速,有关数据库的理论和方法是计算机科学教育领域必不可少的内容。Oracle公司是数据库技术领域的佼佼者,其主打的商用数据库管理系统Oracle经过多年的发展,目前最新的版本为Oracle 10g。市场上关于Oracle的书籍林林总总,各有千秋,但其中很大一部分都偏重于介绍Oracle的具体应用。
Arthur C. Clarke曾经说过,任何足够高级的技术几乎都和魔术没有什么区别。我完全相信这种说法是正确的。在此之后,有人也说过,任何知识足够丰富的技术人员几乎与魔术师没有什么区别。牢记这一点,眼下的这本书实际上就是讲“魔术”的。但是,从我认识本书的作者Jonathan Lewis那天起(我们认识有11年了,从Google回溯到新闻组时代),他就从来不满足于做一名“魔术师”。他乐于搞清楚某件事情为什么是按照那种方式执行的。因此,他的书都是关于“理解”的。更为准确地说,都是关于对Oracle中基于成本的优化器(Cost Based Optimizer,CBO)、它的工作方式以及它的工作原理的理解。
展开
前 言
我在Practical Oracle 8i一书的前言中曾经提到“如果我们想写一本关于Oracle的技术性书籍,那么在写完时,里面的内容肯定已经过时”。Addison-Wesley公司出版这本书的时候正好是Larry Ellison声明发布Oracle 9i的官方版本之时。这本书出版后两个星期,我接到了第一封E-mail询问是否已经计划撰写一本关于Oracle 9i的书。
在此之前,我拒绝了所有关于“升级”的请求,这是基于以下3个原因:(a)这需要太多的精力,(b)在我可以将Oracle 9i的信息融入到本书中之前,可能需要两年的时间来熟悉9i,(c)它仍然只是前面这本书的简单修改。
因此,我的计划就是:2003年9月开始撰写这本书(确实是2003年,我花了22个月的时间才写完),正好是我决定撰写Practical Oracle 8i的4年之后。(请记住,在1999年9月,如果一个Oracle专家不会调试已经40岁高龄的COBOL语言,那么不会有哪家公司会雇佣他)。我花费了大量的时间来学习Oracle 9i,以保证能够学习一些全新的内容。当然,在这4年中,出现了很多Oracle 8i的升级版本(最终版为8.1.7.4),出现了Oracle 9i的两个主要版本,当开始撰写本书时,Oracle公司已经推出了Oracle 10g。因此,我撰写Practical Oracle 9i这一想法可能已经过时了。
事实上,当结束了本书的撰写工作之后(2005年6月),针对Oracle 10g R2的Linux端口已经在OTN上可用了!因此,您阅读本书之后所做的第一件事情就应该是在10g R2下运行本书的示例,以检查究竟有哪些地方发生了变化。
本书并不是对Practical Oracle 8i的简单升级,本书中介绍了关于基于成本优化的相关知识。这看起来是一个非常简单的任务—— 针对优化器所执行的操作和为什么执行这样的操作我可以谈上几个钟头;但是我要做的是要把这些知识成书出版。
遗憾的是,这一任务比想象的要困难得多。把很多词语堆砌起来是比较容易的—— 但是将它们组织成为一本比较有用的结构良好的书籍却是另一回事。给我关于CBO的一些问题,我能够解释其中的原因—— 也许是在创建和测试了一些理论之后。但是,要想为其他人解释关于优化器的一些通用的信息并让他们也能得出同样的结果,这完全不是一码事。
最终,我成功地构建了本书的框架,并意识到必须撰写3本书:基础知识、某些增强的内容和所有的外围知识。本书专门介绍关于基于成本的优化的基础知识。
0.1 写作本书的动机
为什么需要了解CBO的工作原理呢?这是因为当遇到优化器产生的执行计划非常差的情况时,需要理解这究竟是什么问题导致的,并给出正确的修复方法。
当然,我们可以通过为SQL添加一些提示或者进行一些巧妙的代码重写操作的方式来修复一些问题,但是如果采用这两种方式,当同样的问题出现在其他地方时,就必须一再重复执行类似的操作。
从另一方面讲,如果理解了问题的本质内涵,那么就可以一次性地修复该问题,而且在其他地方出现同样的问题时就可以知道该如何解决。
0.2 本书内容
本书涵盖了关于优化的基本信息。本书并不是为了成为优化器工作原理的完全参考手册—— 本书一共有14章,但是直到第10章才提到连接,由此您可能会意识到其中有大量的内容需要介绍。
优化过程中常见的重要术语有:
● 选择率(selectivity)和基数(cardinality):谓词将标识多少数据片断以及可以转换为多少数据行。
● 访问路径(access path):当访问表时,查询应该使用B树索引、联合使用一对位图索引,还是完全忽略索引。
● 连接顺序(join order):查询应该首先访问哪一个表,为了获得指定的结果,从何处开始工作量最少。
虽然有时候我也会对需要考虑的一些微妙特性作些注释,但是,本书实际上只着重于少数核心概念的介绍。优化器如何计算谓词将产生多少数据?它如何用一个数值来表示表扫描的工作,如何将其与使用索引所需的工作进行对比?用哪些数据来估计排序或散列连接所用到的资源?
我可以分析一个查询、查询中的对象以及10053 trace文件,并解释某条路径为什么比另一条路径优先使用。遗憾的是,我无法保证读者每次都能获得与书中trace文件同样的结果,因为示例中无法调试所有的选项(我从来也没有使用过全部的选项),那样的话本书将变成一本非常冗长乏味的书。
尽管本书无法解决所有的问题,但是,我相信本书已经给出了所有的基本方法,利用它们可以解释绝大部分情况下的问题。
0.3 本书中没有包含的内容
本书不可避免地会忽略一些内容。有些内容被忽略是因为它们不属于优化器的核心行为,还有一些被忽略是因为不是很常用,出于篇幅的原因必须排除在外。
本书根本没有提到基于规则的优化器(Rule Based Optimizer,RBO),这是因为每个人都应尽量避免使用它。本书也没有介绍关于可扩展优化器的任何信息(包括上下文和空间索引),这是因为它们不是主流主题。本书也没有提到分析函数、模型子句(10g)和OLAP (联机分析处理),这是因为它们在进行自身类型的数据处理之前必须获取相关的数据—— 而数据获取可能是时间要求最严格的工作。
本书没有提到对象—— 这是因为就优化器而言,它们并不存在。当您创建一个对象类型并创建对象类型的数据片断时,Oracle会将它们转换为简单的表和索引—— 优化器根本不关心对象。
最后,本书几乎没有介绍并行查询、分区表、分布式查询和Oracle中一些比较微妙的物理选项,比如群集和IOT。这出于以下两个原因:第一,篇幅不够;第二,避免影响对主题的介绍。对于优化器来说,存在多种不同的知识信息,要想集中介绍某一种知识将非常困难,因此,最好的办法就是在某个时间段内只介绍一部分知识。
0.4 本系列其他两本书中将出现的内容
本书是这一系列中的第一本。接下来的两本将介绍Oracle中的一些重要特性,尤其是分区表、并行执行、索引组织表、动态采样和查询重写。
对本书中已经提到的一些知识也将进一步进行介绍,比如B树索引的更多访问路径、群集访问和索引访问之间的比较以及其关于直方图的更为详细的信息。
关于基于成本优化的信息的最后一部分是支持优化的基础结构,有助于理解基于成本的优化。此处主要的问题是理解并解释执行计划,理解提示的含义并应用提示,最有效地使用dbms_stats包。
本书是基于Oracle 9.2撰写的,其中注意了与8i的一些区别,并介绍了Oracle 10g中对应内容的变化。接下来的两本书将基本上不介绍8i,更多地介绍Oracle 10g。
0.5 本书组织结构
本书一共14章,按照顺序涵盖了如下主题:
● 表扫描:比较简单,作为入门,介绍了一些关于CPU成本计算的知识。
● 简单选择率:只有一个表,但包含了大量的关于算法的知识。
● 简单B树索引:单块读取和多块读取的区别。
● 群集因子:这也许是索引中最关键的特性。
● 更微妙的选择率:介绍一个基本主题上的大量微小变化。
● 直方图:为什么需要直方图,并介绍了OLTP和DSS/DW之间的区别。
● 位图索引:并不是所有的索引都是相同的。
● 变换:看到的不一定是得到的。
● 连接:用4整章的内容来介绍两个表之间的连接。
● 10053 trace:演示性示例。
● 升级问题:从本书其余部分整理的警告和注意信息的集合。
每一章中都包含很多代码,它们都来自于一组SQL脚本,可以从Apress网站(www.apress.com)或www.tupwk.com.cn/downpage上下载。您可以在自己的系统上运行这些脚本,以重新产生和分析本书中给出的结果。必须认真地分析这些脚本,因为其中包含的一些额外注释和额外测试在书中并没有提及。我同时还在自己的个人网站(www.jlcomp.demon.co.uk)上公布了这些脚本,并不时地增加新的内容。
这些脚本非常重要—— 如果进行修改,会对生产系统产生严重的影响。如果采用脚本来测试基本机制,则可以在每次升级时都重新运行这些测试,以观察会出现什么样的变化。
需要注意的一点是书中出现的脚本中经常会包含一些代码行来标准化测试环境, 例如:
alter session set "_optimizer_system_stats_usage" = false;
不要因为本书中使用了就在生产系统中使用这样的命令。这并不是一个很好的编程习惯;采用这样的命令的目的在于避免当某个数据库(比如)的系统统计信息和另外一个的完全不同时所导致的副作用。
联机代码包中还包括3个init.ora文件和1个用于在Oracle 9i和10g下创建测试表空间tablespace的脚本。这4个文件必须被重新编辑,以避免出现文件路径命名导致的问题;Oracle 9i和10g下的init.ora文件也必须进行调整以适应于rollback/undo的管理选项。我选择针对Oracle 9i和10g运行init.ora文件以避免spfile的偶然变化,但是,您也可以选择将init.ora文件中的设置组合到spfile中。
0.6 必须指出的警告
每当有人要求我为Practical Oracle 8i一书签名时,我总是在签名的后面附上自己的座右铭:尽信书则不如无书(Never believe all you read)。(如果您要求我为本书签名,座右铭将是:印在书上的并不都是真理(Just because it’s printed, doesn’t mean it’s true))。因为总是会有一些特殊情况、不同的参数设置方式和bug是书中没有介绍的。(不用说我所不知道的数千种知识,就是我所知道的也不能保证全部正确。)
参见如下的简单示例(联机代码包中的脚本in-list.sql)—— 在一个本地托管的表空间中运行,采用手动片断空间管理,8KB的块大小:
create table t1 as
select
trunc((rownum-1)/100) n1,
rpad(x,100) padding
from
all_objects
where
rownum <= 1000
;
-- 此处使用dbms_stats收集统计信息
set autotrace traceonly explain
select *
from t1
where
n1 in (1,2)
;
由于采用了函数trunc(),因此,列n1的值为0~9,每个值出现100次。因此,以上查询将返回200行数据。首先在Oracle 8.1.7.4下运行该测试,然后在Oracle 9.2.0.6下运行,并检查autotrace报告的基数。得到如下结果:
Execution Plan (8.1.7.4 autotrace)
----------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=190 Bytes=19570)
1 0 TABLE ACCESS (FULL) OF T1 (Cost=3 Card=190 Bytes=19570)
Execution Plan (9.2.0.6 autotrace)
----------------------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=4 Card=200 Bytes=20400)
1 0 TABLE ACCESS (FULL) OF T1 (Cost=4 Card=200 Bytes=20400)
在 8.1.7.4下,优化器估计得出190行数据作为结果集的基数。在9.2.0.6下,优化器估计得出200行数据作为结果集的基数。这个结果是正确的—— 这是优化器代码中的因此误差被修正后的结果。
在Oracle 9i发布之前,我花了3天时间进行观察,发现8i中的计算看起来好像考虑了当混合索引访问路径和in-list之后的优点。Oracle 9i发布之后,我重新运行了以上测试,终于意识到这并不是Oracle 8i中巧妙的计算,而是一个bug。(参见第3章以获取更为详细的信息。)
因此,如果您的经历正好与我的相反,那么可能就是您的配置笔者未见过—— 我半生以来仅仅接触过几百个数据库,但世界上肯定会有数百万种不同的配置和数据分布形式的组合。绝大部分情况下,下载的代码都能产生与本书相同的结果—— 因此,至少您可以检查书中的测试示例,在自己的系统中得到的结果是否与预测的相一致。不管结果如何,会得到一些线索,可以推断出为什么您的观察与书中所描述的不同。
将前面的谓词
where n1 in (1,2);
修改为
where n1 in (11, 12);
并将字面值修改为较大的值,比较一下9.2.0.6下和10.1.0.4下的结果之异同,这一点留给读者作为练习。结果将令人非常吃惊—— 第3章中将进行进一步分析。
0.6.1 理论与实践
阅读本书时要记住,运行一个查询有两个独立的阶段。首先,优化器确定它“认为”将发生什么事情,然后运行时引擎执行应执行的任务。
理论上讲,优化器应该了解、描述并且将它的计算过程基于猜想运行时引擎会执行的动作。实际上,优化器和运行时引擎有时候对于应该执行什么样的任务其想法是不一致的。
0.6.2 解释计划
在本系列后续图书中,我将描述获取执行计划的方法,并列出为什么产生的计划会是错误的,或者至少是造成误导的各种原因。目前,本书为了简单起见,其中绝大部分示例都是利用autotrace或者dbms_xplan包来产生执行计划。
然而,当我实际应用中遇到一个问题,并且没有理由质疑这些理论工具时,我可能会选择运行所有的问题查询,以查看10053 trace文件、10046 trace文件中的统计信息和v$sql_plan的内容。对于包含了分区对象或者并行执行任务的情况,我可能会选用另外一组追踪事件来分析其中的详细信息,否则,这些详细信息在任何形式的执行计划中都看不到。
所有用于产生和分析执行计划的工具都存在一些缺陷。不能因为本书中仅仅使用了autotrace和dbms_xplan就简单地依赖它们。
0.7 结论
当读完本书之后(第一次),希望您能够记住以下3个关键信息。
首先,通常情况下,对于商业问题来说,可能在优化器可用的执行路径中存在良好的解决方案。我们仅仅需要找出并使用这个路径。
其次,任何人都能够创建较好的和递增的测试,测试开始比较小且简单,但是,当条件允许也只有当条件允许时,测试的规模和复杂度都将增加。
最后,如果发现了一个性能问题,而且能够将其定位于数据内容,并且清楚访问需求和物理存储策略,那么我们就学会了本书中最重要的知识。
0.8 测试用例
下载包中对应于前言的文件如表0-1所示:
表0-1 前言的测试用例
脚 本 注 释
in_list.sql 演示in-list循环中的选择率计算的变化
setenv.sql 为SQL*Plus设置标准化环境
序
Arthur C. Clarke曾经说过,任何足够高级的技术几乎都和魔术没有什么区别。我完全相信这种说法是正确的。在此之后,有人也说过,任何知识足够丰富的技术人员几乎与魔术师没有什么区别。牢记这一点,眼下的这本书实际上就是讲“魔术”的。
但是,从我认识本书的作者Jonathan Lewis那天起(我们认识有11年了,从Google回溯到新闻组时代),他就从来不满足于做一名“魔术师”。他乐于搞清楚某件事情为什么是按照那种方式执行的。因此,他的书都是关于“理解”的。更为准确地说,都是关于对Oracle中基于成本的优化器(Cost Based Optimizer,CBO)、它的工作方式以及它的工作原理的理解。Jonathan把他对Oracle中CBO的理解通过操作和示例介绍给我们,通过这种方式的介绍,我们学会了新的方法和解决方案。
简单地说,我们可以将Oracle中的CBO看作是一个数学模型;为其提供输入(查询和统计信息),它产生相应的输出(查询计划)。为了能够成功地应用CBO,理解输入信息的含义以及CBO如何使用这些信息是关键。考虑一下以下问题,这个问题我已经多次尝试寻找答案了:收集统计信息的最佳方式是什么?我们应该收集什么样的统计信息?看起来好像比较简单也非常直观—— 应该存在答案,但绝对不存在一个放之四海而皆准的答案。这依赖于具体的情况、数据分布形式、查询和系统的类型(事务的,数据仓库)等许多因素,为了能够回答这个问题,必须能够理解CBO的工作方式以及上面这些因素是如何影响CBO的。
我最喜欢的一章是第7章,这一章非常完美地诠释了直方图是什么、CBO是如何使用直方图的,以及关于直方图的一些神话(对于CBO的输入来说,这是最容易误解的)。我最喜欢这一章的原因之一是我曾经在3年前第一次听说了这一章的内容(注意,不是阅读,而是听说)。这是在3年前的北加利福尼亚Oracle用户群(Northern California Oracle User Group ,NoCOUG)会议上听到的。我参加了Jonathan的Histogram(直方图)分会,第一次感觉真正理解了直方图在Oracle中是如何工作的。Jonathan提供了很多日常使用的实用信息,因此我才能够很好地回答上面这个问题。在本书中,可以发现很多这些日常使用的实用信息的主题。
通过Jonathan在本书中提供的关于基于成本的优化器的知识,DBA可以成为更优秀的设计人员,开发人员可以成为更优秀的SQL编码人员,最终DBA和开发人员都可以成为更优秀的故障诊断人员。Jonathan在书中提供的精细而丰富的示例使得CBO的复杂知识变得容易理解了。
一次又一次的事实说明,如果想安全高效地使用某个工具,就必须理解这个工具的工作原理。对于软件、硬件和生活中的几乎一切事物来说都是这样的。我们眼下的这本书就能够保证我们安全有效地使用Oracle中的CBO工具。
Thomas Kyte
Oracle公司公共事业部副总裁
译者序
我们日常生活的很多方面都离不开数据库的支持,从银行业务、电话缴费乃至小型家庭账本系统都能看到数据库的影子。近年来,数据库技术的发展非常迅速,有关数据库的理论和方法是计算机科学教育领域必不可少的内容。Oracle公司是数据库技术领域的佼佼者,其主打的商用数据库管理系统Oracle经过多年的发展,目前最新的版本为Oracle 10g。
市场上关于Oracle的书籍林林总总,各有千秋,但其中很大一部分都偏重于介绍Oracle的具体应用。与这些书籍不同,这本由Oracle数据库技术大师Jonathan Lewis撰写的《基于成本的Oracle优化法则》着重介绍如何优化Oracle的性能,提高Oracle的效率。
Oracle 提供了基于成本(CostBased)的优化器和基于规则(RuleBased)的优化器,简称为CBO和RBO,用于确定查询操作的执行计划。CBO是依赖于表的一些统计信息来选择最低成本的执行计划,当这些统计信息不准确时,产生的计划便可能不是最佳的。因此,如何正确使用CBO十分重要。本书着重分析CBO的原理和执行过程。
Jonathan Lewis先生用22个月完成的著作,让我们在翻译时不敢松懈,只能加倍努力。这本书理论较深,作者刨根问底,很多关于成本的计算方式十分精细,可能读起来需要一定的耐心,但是如果读者是对程序要求同样精细的人,并且所开发的应用程序要求较高的性能,那么阅读本书将让您受益匪浅。作者成功地将深奥难懂的优化理论变得通俗易懂,在介绍过程中穿插大量的示例,由点及面,全面生动地介绍了相关的优化理论。作者非常注重于将Oracle 10g与Oracle的以前版本(8i和9i)进行比较,如果对Oracle 8i/9i较为熟悉,那么掌握这些新的理论也就是轻而易举的事情了。
本书面向Oracle数据库管理员和对Oracle有一定开发经验的工程人员,也可供数据库优化方面的研究人员阅读。由于本书覆盖面广,时间较紧,翻译难度比较大,虽然在翻译中下了不少功夫,并用了较长的时间进行校对,但在译文中仍难免出现一些疏漏,恳请读者批评指正。
译 者