新書推薦:
《
女人的胜利
》
售價:NT$
254.0
《
数据有道:数据分析+图论与网络+微课+Python编程(鸢尾花数学大系:从加减乘除到机器学习)
》
售價:NT$
1214.0
《
500万次倾听:陪伤心的人聊聊
》
售價:NT$
245.0
《
英国商业500年(见证大国崛起与企业兴衰,启迪未来商业智慧。)
》
售價:NT$
367.0
《
万千心理·儿童心理治疗中的心智化:临床实践指导
》
售價:NT$
398.0
《
自我囚禁的人:完美主义的心理成因与自我松绑(破除你对完美主义的迷思,尝试打破自我评价过低与焦虑的恶性循环)
》
售價:NT$
301.0
《
周易
》
售價:NT$
203.0
《
东南亚的传统与发展
》
售價:NT$
306.0
|
編輯推薦: |
汇聚Oracle专家集体智慧?
内容贴近实战,讲解透彻精彩?
DBA修炼内力必读秘籍
|
內容簡介: |
本书由15位知名技术专家联手打造,每位作者分别用一章的篇幅介绍他们最擅长的PLSQL相关主题,涵盖了PLSQL开发的方方面面。本书作者要么是Oracle社区中坚分子,要么是大名鼎鼎的OakTable成员,而且经常活跃在Oracle技术培训第一线,对PLSQL均有着深入透彻的理解,对解释复杂问题有着简单独到的方法。一册在手,众多PLSQL牛人的真知灼见尽收眼底,你还等什么?
本书着重介绍了PLSQL最新、最实用的特性,从什么该做和什么不该做、怎么做对,以及怎么做更有效率、效果更好等三个部分全面阐释了PLSQL相关的各个主题。而且,每一章都配有非常贴切的示例代码、跟踪图以及输出结果,辅以深入浅出的讲解,令人在恍然大悟之后不禁拍案叫绝。各章内容均涵盖了PLSQL实际开发中的最佳实践,反映了作者多年积累的经验和教训,其价值非同一般。
本书适合具有一定PLSQL经验的读者学习参考。
|
關於作者: |
John Beresniewicz(约翰?贝雷斯尼维奇)是位于加州红木城红木岸(Redwood
Shores)的Oracle总部技术团队的一名咨询顾问。他于2002年加入Oracle,负责企业管理器的数据库性能领域,他对诊断和调优包、实时应用测试、支持工作台和Exadata的设计作出了重要贡献。多年以来,他经常在Oracle全球大会和其他会议上发言,发言主题包括数据库性能和PLSQL编程。他与Steven
Fellerstein合著了Oracle Built-in
Packages(O’Reilly&Associates,1998年)一书,并且是OakTable网络的创始人之一。
Adrian Billington
(阿德里安?比林顿)是应用设计、开发和性能调优方面的顾问。自1999年以来,一直从事Oracle数据库方面的工作。他是www.oracle-developer.net网站的发起人,这个网站为Oracle开发人员提供各种SQL和PLSQL功能、实用工具和技术。阿德里安还是Oracle
ACE,同时也是OakTable网络的成员。现在,他与妻子安吉和三个孩子:格鲁吉亚、奥利弗和伊莎贝拉一起居住在英国。
Martin Büchi
(马丁?步琪)自2004年以来,任Avaloq公司首席软件架构师。该公司是一个标准化的银行软件供应商,其产品基于Oracle
RDBMS构建,包含1100万行PLSQL代码。他与两位同事一起设计了系统架构,并评审了170名全职PLSQL开发人员的设计和代码,以追求软件的简明、效率和健壮性。马丁经常在Oracle大会上发言。2009年,他被Oracle
Magazine评选为PLSQL年度开发人员。从事Oracle数据库工作之前,马丁曾在面向对象的系统、形式化方法和近似记录匹配等领域工作。他拥有瑞士联邦技术研究所的硕士学位和芬兰土尔库计算机科学中心的博士学位。业余时间,马丁喜欢与他的家人一起进行各种户外运动。
Melanie Caffrey
(梅拉妮?卡弗里)是Oracle公司高级开发经理,为不同客户的业务需求提供前端和后端的Oracle解决方案。她是多部技术出版物的合著者,包括Oracle
Web Application Programming for PLSQL Developers、Oracle DBA
Interactive Workbook、Oracle Database Administration: The Complete
Video Course等,这些书全部由Prentice
Hall出版。她在纽约哥伦比亚大学的计算机技术与应用课程中指导学生,教授先进的Oracle数据库管理和PLSQL开发。她也经常在Oracle会议上发言。
Ron
Crisco(罗恩?克里斯科)28年来分别担任软件设计师、开发人员和项目负责人,并有21年的Oracle数据库工作经验。他在R方法(Method
R)公司从事软件设计和开发、软件产品管理(如R方法剖析器、MR工具和MR跟踪)、咨询、教授课程等工作。他的特长是简化复杂的工作,这在帮助他身边的人完成非凡工作时尤显宝贵。
Lewis
Cunningham(刘易斯?坎宁安)在IT领域已经工作了20多年。自1993年以来一直与Oracle数据库打交道。他的专长是应用程序设计、数据库设计,以及大容量的VLDB数据库编码。目前他任职于佛罗里达州圣彼得堡的一家金融服务公司,担任高级数据库架构师,负责超大规模、高事务率分析型数据库和应用程序的工作。他花了大量时间来与最新的技术和趋势保持同步,并在用户组发表演讲,举办网络研讨会。刘易斯也是一位Oracle
ACE总监和Oracle认证专家。他在Oracle技术网发表了数篇文章,并在http:it.toolbox.com
blogsoracle-guide维护一个Oracle技术博客。刘易斯写了两本书:EnterpriseDB: The
Definitive Reference(Rampant Tech press,2007年)和SQL DML: The SQL
Starter
Series(CreateSpace,2008年)。他与他的妻子及两个儿子起住在佛罗里达州。可以通过电子邮件lewisc@databasewisdom.com与他联系。
Dominic Delmolino
(多米尼克?德莫里诺)是Agilex技术公司首席Oracle和数据库技术专家,这是一家专门协助政府和私营企业实现信息价值的咨询公司。多米尼克拥有24年以上的数据库经验,其中担任过20多年的Oracle数据库工程和开发专家。他是OakTable网络的成员,并定期出席各种学术会议、研讨会,以及欧洲和美国的用户组会议。他还维护www.oraclemusings.com网站,该网站专注于与数据库应用程序开发相关的数据库编码和设计实践。多米尼克拥有纽约州伊萨卡康奈尔大学的计算机科学学士学位。
Sue Harper (苏?哈珀)是数据库开发工具组中的Oracle SQL Developer和SQL
Developer数据建模器的产品经理。她自1992年以来一直在Oracle公司工作,目前在伦敦办事处工作。苏是一些杂志的特约撰稿人,维护着一个技术博客,并在世界各地的许多会议上发言。她撰写了技术书籍Oracle
SQL Developer
2.1(Packt,2009),业余时间,苏喜欢步行和摄影。同时,她还花时间到新德里的贫民区做慈善工作,帮助那里的妇女和儿童。
Torben Holm
(托尔?霍尔姆)自1987年以来一直从事开发工作。自1992年以来,他一直致力于与Oracle相关的工作,前四年担任系统分析师和应用程序开发人员(Oracle
7、Forms 4.0Reports 2.0和DBA),然后做了两年开发(ORACLE67、Forms
3.0和RPT以及DBA)。他在Oracle丹麦公司的高级服务组工作了数年,担任首席高级顾问,执行应用程序开发和DBA任务。他还担任过PLSQL、SQL和DBA课程的讲师。现在,托尔在Miracle
AS(www.miracleas.dk)工作,担任顾问,负责应用开发(PLSQL、mod_plsql、Forms、ADF)和数据库管理。10年来他一直在
Miracle AS公司工作。他是Oracle认证开发人员,并且也是OakTable网络成员。
Connor McDonald (康纳?麦当劳)自20世纪90年代初一直从事Oracle相关工作,他非常熟悉Oracle
6.0.36和Oracle
7.0.12。在过去11年中,康纳曾为位于西欧、东南亚、澳大利亚、英国和美国的公司开发过系统。他已经认识到,虽然世界各地的系统及方法非常多样,但开发在Oracle上运行的系统往往有两个共同的问题:要么避免使用Oracle特定的功能,要么就是采取不太理想的用法或随意乱用它们。正是这种观察,促使他创建了一个提示和技巧的个人网站(www.oracledba.co.uk),并努力在Oracle演讲者组织中发表更多演讲,以提高PLSQL的业内认知度和普及度。
Arup Nanda (奥雅纳?南大)自1993年以来,一直是Oracle
DBA,他熟悉数据库管理的所有方面,从建模到灾难恢复。目前,他在纽约州白原市的喜达屋酒店(即喜来登、威斯汀等连锁酒店的母公司)领导全球DBA团队。他是独立Oracle用户协会(IOUG)旗下出版物SELECT
Journal的特约编辑,在许多Oracle技术盛会,如Oracle全球和本地用户组(如纽约Oracle用户组)中发表演讲,并为印刷出版物如Oracle
Magazine和网络出版物如Oracle Techndogy Network撰写了许多文章。奥雅纳与他人合著了两本书:Oracle
Privacy Security Auditing(Rampant,2003年)和Oracle PLSQL for
DBAs(O’Reilly,2005年)。由于他的专业成就和对用户社区的贡献,Oracle评选他为2003年年度DBA。奥雅纳与他的妻子Anindita和儿子阿尼什住在康涅狄格州的丹伯里。可以通过arup@proligence.com联系他。
Stephan Petit
(斯蒂芬?佩蒂特)于1995年在位于瑞士日内瓦的欧洲粒子物理实验室(CERN)开始了他的职业生涯。他现在是一个软件工程师和学生团队的负责人,负责为实验室和其他部门提供应用程序和工具。工程和设备数据管理系统是这些工具之一,也称为CERN
EDMS。像CERN的大型强子对撞机(LHC)项目有40年或以上的生命周期。
EDMS是实验室的数字化工程的内存记忆体。电子文件管理系统中存储了与一百多万件设备有关的一百多万份文件,EDMS也供CERN的产品生命周期管理(PLM)和资产跟踪系统使用。
EDMS几乎完全是基于PLSQL的,并旨在拥有一个至少与LHC一样长的生命周期。
斯蒂芬和他的团队一直在完善PLSQL编码规范和最佳实践,以满足他们非常有趣的各种挑战的组合:几十年的可维护性、可靠性、高效的错误处理、可扩展性、模块的可重用性。团队成员的频繁轮换,其中大部分只是暂时在CERN实习的学生,加剧了这些挑战。最古老的一段代码是在1995年写的,现在仍然在使用——并且成功地运行!除了完善PLSQL,斯蒂芬还喜欢不时登台表演,比如担任CERN摇滚夏季音乐节的摇滚乐队歌手,以及在多部戏中出演角色。
Michael Rosenblum
(迈克尔?罗森布鲁姆)是Dulcian公司的软件架构师开发DBA,他负责系统调优和应用程序架构。迈克尔通过编写复杂的PLSQL例程和研究新功能支持Dulcian开发人员。他是PLSQL
for Dummies(Wiley,2006年)一书的作者之一,并在IOUG Select Journal和ODTUG Tech
Journal发表了许多篇与数据库相关的文章。迈克尔是一位Oracle
ACE,也经常出席不同地区和国家的Oracle用户组大会(Oracle OpenWorld大会、ODTUG、IOUG
Collaborate、RMOUG、NYOUG等),他是ODTUG万花筒2009年“最佳演讲奖”得主。在他的家乡乌克兰,他获得了乌克兰总统奖学金,并拥有信息系统理学硕士学位并以优异成绩获得基辅国立经济大学毕业证书。
Robyn Sands
(罗宾?桑兹)是思科系统公司的软件工程师,她为思科的客户设计和开发嵌入式Oracle数据库产品。自1996年以来,她一直使用Oracle软件,并在应用开发、大型系统实现和性能测量方面具有丰富经验。罗宾的职业生涯始于工业工程和质量工程,她将自己对数据的挚爱结合到以前接受的教育和工作经验中,寻找新方法来建立性能稳定、易于维护的数据库系统。她是OakTable网络成员,并是下面两本Oracle书籍的作者之一:Expert
Oracle Practices和Pro Oracle
SQL(都由Apress出版,2010)。罗宾偶尔在http:adhdocddba.
blogspot.com发表一些博客。
Riyaj
Shamsudeen是OraInternals公司首席数据库管理员和主席,这是一家从事性能调优数据库恢复EBS11i等领域的咨询公司。他专门研究真正的应用集群(RAC)、性能调优和数据库内部结构。他还经常在其博客http:orainternals.wordpress.com上发表这些技术领域的文章。他也经常出席许多国际会议,如HOTSOS、COLLABORATE、RMOUG、SIOUG、UKOUG等,他是OakTable网络的骄傲一员。他拥有16年以上使用Oracle技术产品的经验,并担任了15年以上的OracleOracle应用程序数据库管理员。
译者简介:
卢涛
1995年参加工作,高级程序员、系统分析师、高级工程师。2004年起接触Oracle数据库,获得Oracle数据库管理9i至11g、PLSQL开发、性能优化、RAC管理、数据仓库等多个OCP、OCE、OCS认证。ITPUB社区Oracle开发版版主,《剑破冰山——Oracle开发艺术》一书合著者。做过需求分析、系统分析、架构设计、数据库和应用程序性能优化等工作。参与数次全国性普查数据处理系统的设计、开发和运维。
校审
苏旭晖
在IT行业摸爬滚打20多年,1997年至今一直致力于Oracle开发,擅长用SQL、PLSQL。ITPUB社区Oracle开发版版主,以及《剑破冰山——Oracle开发艺术》一书合著者。现居加拿大多伦多,从事数据库应用系统的设计与开发工作。出国前任职于厦门巨龙软件公司。多年来致力于金融、公安、医疗、社保等行业软件的研发。
李颖
2006年毕业于渤海大学英语系,主修英语教育专业。英语爱好者
贾书民
河北省统计局数据管理中心调研员,高级程序员、高级工程师。有多年Unix系统管理、数据库系统管理与设计、数据处理软件开发经验。1993年起开始使用Oracle开发了《河北省综合数据库系统》等多个大型应用系统。参与过《第五次全国人口普查数据处理系统》等多个国家级项目的设计和开发。擅长使用SQL、PLSQL进行高效数据分析处理。所开发项目获第四届全国统计科学技术进步一等奖。此外,他还参与编写《剑破冰山——Oracle开发艺术》一书。
|
目錄:
|
第1章 避免误用
1.1 逐行处理
1.2 嵌套的逐行处理
1.3 查找式查询
1.4 对DUAL的过度访问
1.4.1 日期的算术运算
1.4.2 访问序列
1.4.3 填充主—从行
1.5 过多的函数调用
1.5.1 不必要的函数调用
1.5.2 代价高昂的函数调用
1.6 数据库链接调用
1.7 过度使用触发器
1.8 过度提交
1.9 过度解析
1.10 小结
第2章 动态SQL:处理未知
2.1 动态SQL的三种方式
2.1.1 本地动态SQL
2.1.2 动态游标
2.1.3 DBMS_SQL
2.2 动态思考的样例
2.3 安全问题
2.4 性能和资源利用率
2.4.1 反模式
2.4.2 比较动态SQL的实现
2.5 对象的依赖关系
2.5.1 负面影响
2.5.2 正面影响
2.6 小结
第3章 PLSQL和并行处理
3.1 为什么需要并行处理
3.2 影响并行处理的定律
3.3 大数据的崛起
3.4 并行与分布式处理
3.5 并行硬件体系结构
3.6 确定目标
3.6.1 加速
3.6.2 按比例扩展
3.6.3 并行度
3.7 用于并行处理的候选工作负载
3.7.1 并行和OLTP
3.7.2 并行和非OLTP工作负载
3.8 MapReduce编程模型
3.9 在使用PLSQL之前
3.10 可用于并行活动的进程
3.11 使用MapReduce的并行执行服务器
3.11.1 管道表函数
3.11.2 指导
3.11.3 并行管道表函数小结
3.12 小结
第4章 警告和条件编译
4.1 PLSQL 警告
4.1.1 基础
4.1.2 使用警告
4.1.3 升级警告为错误
4.1.4 忽略警告
4.1.5 编译和警告
4.1.6 关于警告的结束语
4.2 条件编译
4.2.1 基础
4.2.2 正在运行代码的哪部分
4.2.3 预处理代码的好处
4.2.4 有效性验证
4.2.5 控制编译
4.2.6 查询变量
4.2.7 关于条件编译的结束语
4.3 小结
第5章 PLSQL单元测试
5.1 为什么要测试代码
5.2 什么是单元测试
5.2.1 调试还是测试
5.2.2 建立测试的时机
5.3 单元测试构建工具
5.3.1 utPLSQL:使用命令行代码
5.3.2 Quest Code Tester for Oracle
5.3.3 Oracle SQL Developer
5.4 准备和维护单元测试环境
5.4.1 创建单元测试资料档案库
5.4.2 维护单元测试资料档案库
5.4.3 导入测试
5.5 构建单元测试
5.5.1 使用单元测试向导
5.5.2 创建第一个测试实施
5.5.3 添加启动和拆除进程
5.5.4 收集代码覆盖率统计信息
5.5.5 指定参数
5.5.6 添加进程验证
5.5.7 保存测试
5.5.8 调试和运行测试
5.6 扩大测试的范围
5.6.1 创建查找值
5.6.2 植入测试实施
5.6.3 创建动态查询
5.7 支持单元测试功能
5.7.1 运行报告
5.7.2 创建组件库
5.7.3 导出、导入和同步测试
5.7.4 构建套件
5.8 从命令行运行测试
5.9 小结
第6章 批量SQL操作
6.1 五金商店
6.2 设置本章的例子
6.3 在PLSQL中执行批量操作
6.3.1 批量获取入门
6.3.2 三种集合风格的数据类型
6.3.3 为什么要自找麻烦
6.3.4 监控批量收集的开销
6.3.5 重构代码以使用批量收集
6.4 批量绑定
6.4.1 批量绑定入门
6.4.2 度量批量绑定性能
6.4.3 监视内存的使用
6.4.4 11g中的改进
6.5 批量绑定的错误处理
6.5.1 SAVE EXCEPTIONS和分批操作
6.5.2 LOG ERRORS子句
6.5.3 健壮的批量绑定
6.6 大规模集合的正当理由
6.7 真正的好处:客户端批量处理
6.8 小结
第7章 透识你的代码
7.1 本章内容取舍
7.2 自动代码分析
7.2.1 静态分析
7.2.2 动态分析
7.3 执行分析的时机
7.4 执行静态分析
7.4.1 数据字典
7.4.2 PLScope
7.5 执行动态分析
7.5.1 DBMS_PROFILER和DBMS_TRACE
7.5.2 DBMS_HPROF
7.6 小结
第8章 合同导向编程
8.1 契约式设计
8.1.1 软件合同
8.1.2 基本合同要素
8.1.3 断言
8.1.4 参考文献
8.2 实现PLSQL合同
8.2.1 基本的ASSERT程序
8.2.2 标准的包本地断言
8.2.3 使用ASSERT执行合同
8.2.4 其他改进
8.2.5 合同导向函数原型
8.3 示例:测试奇数和偶数
8.4 有用的合同模式
8.4.1 用NOT NULL输入且输出NOT NULL
8.4.2 函数返回NOT NULL
8.4.3 布尔型函数返回NOT NULL
8.4.4 检查函数:返回TRUE或ASSERTFAIL
8.5 无错代码的原则
8.5.1 严格地断言先决条件
8.5.2 一丝不苟地模块化
8.5.3 采用基于函数的接口
8.5.4 在ASSERTFAIL处崩溃
8.5.5 对后置条件进行回归测试
8.5.6 避免在正确性和性能之间取舍
8.5.7 采用Oracle 11g优化编译
8.6 小结
第9章 从SQL调用PLSQL
9.1 在SQL中使用PLSQL函数的开销
9.1.1 上下文切换
9.1.2 执行
9.1.3 欠理想的数据访问
9.1.4 优化器的难点
9.1.5 读一致性陷阱
9.1.6 其他问题
9.2 降低PLSQL函数的开销
9.2.1 大局观
9.2.2 使用SQL的替代品
9.2.3 减少执行
9.2.4 协助CBO
9.2.5 调优PLSQL
9.3 小结
第10章 选择正确的游标
10.1 显式游标
10.1.1 解剖显式游标
10.1.2 显式游标和批量处理
10.1.3 REF游标简介
10.2 隐式游标
10.2.1 解剖隐式游标
10.2.2 隐式游标和额外获取的理论
10.3 静态REF游标
10.3.1 详细的游标变量限制清单
10.3.2 客户端和REF游标
10.3.3 有关解析的话题
10.4 动态REF游标
10.4.1 例子和最佳用法
10.4.2 SQL注入的威胁
10.4.3 描述REF游标中的列
10.5 小结
第11章 大规模PLSQL编程
11.1 将数据库作为基于PLSQL的应用服务器
11.1.1 案例研究:Avaloq银行系统
11.1.2 在数据库中使用PLSQL实现业务逻辑的优势
11.1.3 用数据库作为基于PLSQL的应用程序服务器的限制
11.1.4 软因素
11.2 大规模编程的要求
11.3 通过规范实现一致性
11.3.1 缩写词
11.3.2 PLSQL标识符的前缀和后缀
11.4 代码和数据的模块化
11.4.1 包和相关的表作为模块
11.4.2 含有多个包或子模块的模块
11.4.3 模式作为模块
11.4.4 在模式内部模块化
11.4.5 用模式模块化与在模式内模块化的比较
11.5 使用PLSQL面向对象编程
11.5.1 使用用户定义类型的面向对象编程
11.5.2 使用PLSQL记录面向对象编程
11.5.3 评估
11.6 内存管理
11.6.1 测量内存使用
11.6.2 集合
11.7 小结
第12章 渐进式数据建模
12.1 从二十年的系统开发中总结的经验
12.2 数据库和敏捷开发
12.3 渐进式数据建模
12.4 重构数据库
12.5 通过PLSQL创建访问层
12.6 敏捷宣言
12.7 用PLSQL进行渐进式数据建模
12.7.1 定义接口
12.7.2 思考可扩展性
12.7.3 测试驱动开发
12.7.4 明智地使用模式和用户
12.8 小结
第13章 性能剖析
13.1 何谓性能
13.1.1 功能需求
13.1.2 响应时间
13.1.3 吞吐量
13.1.4 资源利用率
13.1.5 性能是功能的一种
13.2 什么是剖析
13.2.1 顺序图
13.2.2 概要文件之神奇
13.2.3 性能剖析的好处
13.3 性能测量
13.3.1 这个程序为什么慢
13.3.2 测量嵌入
13.3.3 识别
13.3.4 条件编译
13.3.5 内建的剖析器
13.3.6 扩展的SQL跟踪数据(事件10046)
13.3.7 针对Oracle的测量工具库(ILO)
13.4 问题诊断
13.4.1 R方法
13.4.2 ILO示例
13.4.3 剖析示例
13.5 小结
第14章 编码规范和错误处理
14.1 为什么要制订编码规范
14.2 格式化
14.2.1 大小写
14.2.2 注释
14.2.3 比较
14.2.4 缩进
14.3 动态代码
14.4 包
14.5 存储过程
14.5.1 命名
14.5.2 参数
14.5.3 调用
14.5.4 局部变量
14.5.5 常量
14.5.6 类型
14.5.7 全局变量
14.5.8 本地存储过程和函数
14.5.9 存储过程元数据
14.6 函数
14.7 错误处理
14.7.1 错误捕获
14.7.2 错误报告
14.7.3 错误恢复
14.7.4 先测试再显示
14.8 小结
第15章 依赖关系和失效
15.1 依赖链
15.2 缩短依赖链
15.3 数据类型引用
15.4 用于表修改的视图
15.5 把组件添加到包
15.6 依赖链中的同义词
15.7 资源锁定
15.8 用触发器强制执行依赖
15.9 创建最初禁用的触发器
15.10 小结
|
內容試閱:
|
避免误用
Riyaj Shamsudeen
感谢您购买本书。PLSQL是你值得拥有的好工具,不过,你应当理解PLSQL并不适用于所有场景。本章将讲述何时使用PLSQL编写应用程序,怎样编写可扩展的代码,更重要的是,何时不使用PLSQL编写代码。滥用某些PLSQL的结构会导致不可扩展的代码。本章将讨论大量的案例,它们因误用PLSQL而不可扩展。
PLSQL 与 SQL
SQL是一门集合处理的语言,如果以集合级别的思维编写SQL语句,则会使其具有更好的可扩展性。PLSQL是过程语言,而SQL语句可以嵌入到PLSQL代码中。
SQL语句在SQL执行器(也就是通常说的SQL引擎)中执行。PLSQL语句则由PLSQL引擎执行。PLSQL的威力在于能将PLSQL的过程化数据处理能力和SQL的集合处理能力结合起来。
1.1 逐行处理
在一个典型的逐行处理程序中,代码首先打开一个游标,然后遍历从游标返回的行,并且处理每一行数据。这种基于循环的处理方式是非常不赞成使用的,它会导致不可扩展的代码。代码清单1-1显示了一个使用这种结构的例子。
代码清单1-1 逐行处理
在代码清单1-1中,程序声明了一个游标c1,然后用游标for循环隐式地打开了这个游标,对从游标c1取出的每一行,程序查询customers表,并把first_name和last_name的值填充到变量,随后插入一行数据到top_sales_customers表。
代码清单1-1的编程方法很有问题。即使在循环中调用的SQL语句是高度优化的,程序的执行还是会消耗大量时间。假设查询customers表的SQL语句消耗0.1秒,INSERT语句也消耗0.1秒,那么在循环中每次执行就要0.2秒。如果游标c1取出了100
000行,那么总时间就是100 000乘以0.2秒,即20
000秒,也就是大约5.5小时。很难去优化这个程序的结构。基于显而易见的理由,Tom
Kyte把这种处理方式定义为慢之又慢的处理(slow-by-slow processing)。
注意
本章的例子采用SH模式(schema),这是Oracle公司提供的范例模式之一。要安装这个范例模式,Oracle提供了安装软件。可以从http:download.oracle.comotnsolarisoracle11g
R2solaris.sparc64_11gR2_examples.zip下载Solaris平台11gR2版本的样例软件。软件解压缩后的目录中含有安装说明。Oracle网站也提供了其他平台和版本的范例软件的Zip压缩包。
代码清单1-1的代码还有一个固有的问题。从PLSQL的循环中调用的SQL语句会反复在PLSQL引擎和SQL引擎之间切换执行,这种两个环境之间的切换称作上下文切换。上下文切换增加了程序运行的时间,并增加不必要的CPU开销。你应当通过消除或减少这种两个环境之间的切换来减少上下文切换的次数。
一般应当禁止逐行处理,更好的编程实践是把代码清单1-1的程序转换成一个SQL语句。代码清单1-2重写了代码,完全避免了PLSQL。
代码清单1-2 重写逐行处理的代码
代码清单1-2除了解决逐行处理的缺陷以外,还有更多的优势。重写后的SQL语句可以使用并行执行来调优,使用多个并行执行进程可以大幅地减少执行时间。并且,代码变得简明且可读性强。
注意
如果将PLSQL的循环代码重写为连接(join),需要考虑重复问题。如果在customers表中cust_id列有重复值,那么重写后的SQL语句取回的行比你想要的行多。不过,在这个特定的例子中,customers表的cust_id列上有主键,因此在cust_id列上使用等值连接不存在重复的危险。
1.2 嵌套的逐行处理
在PLSQL语言中游标可以嵌套使用。首先将数据从一个游标中取出,然后将这些值传给另一个游标,即二级游标,再从二级游标取值传给三级游标,以此类推,这是很常见的编程方法。但是如果游标嵌套很深,这种基于循环的代码导致的性能问题就会加剧。由于游标嵌套,SQL执行的次数大量增加,导致程序运行时间更长。
在代码清单1-3中,c1、c2和c3是嵌套游标。游标c1是顶级游标,从表t1取得数据,c2是开放游标,传递从游标c1取得的值,c3也是开放游标,传递游标c2取得的值。有一个UPDATE语句对游标c3返回的每一行执行一次。尽管UPDATE语句已经优化为执行一次只要0.01秒,但程序的性能还是会由于深度嵌套游标而难以忍受的。假设游标c1、c2和c3分别返回20、50和100行,那么上述代码需要循环100
000行,程序的总执行时间超过了1000秒。对这类程序的调优通常需要完全重写它。
代码清单1-3 用嵌套游标逐行处理
代码清单1-3中代码的另一个问题在于先执行一个UPDATE语句。如果UPDATE
语句产生了no_data_found异常,那么再执行一个INSERT语句。这种类型的问题可以利用MERGE语句从PLSQL转到SQL引擎处理。
从概念上讲,代码清单1-3中的三重循环表示表t1、t2和t3之间的等值连接。代码清单1-4展示了根据上述逻辑改写的使用表别名t的SQL语句。UPDATE和INSERT逻辑的结合用MERGE语句代替,MERGE语法提供了更新存在的行和插入不存在的行的功能。
代码清单1-4 用MERGE语句重写逐行处理
不要在PLSQL语言中编写深度嵌套游标的代码。审查这类代码的逻辑,看是否能用SQL语句来代替。
1.3 查找式查询
查找式查询(lookup
query)一般用于填充某些变量或执行数据的合法验证。但在循环中执行查找式查询会导致性能问题。
在代码清单1-5中,高亮显示的部分就是使用查找式查询来得到country_name值。程序对游标c1中的每一行都要执行一个查询来取得country_name的值。当从游标c1中取得的行数增加时,执行查找式查询的次数也增加了,这导致代码的效率低下。
代码清单1-5 查找式查询,对代码清单1-1的副本的修改
代码清单1-5的代码是过分简化的,对country_name的查找式查询实际上可以重写为主游标c1本身中的一个连接。第一步,应将查找式查询修改为连接,可是在实际的应用程序中,并不一定可以实现这种改写。
如果无法利用改写代码来减少查找式查询的执行次数,那么还有另一个选择。你可以定义一个关联数组来缓存查找式查询的结果,以便在随后的执行中重用这个数组,这样也能有效地减少查找式查询的执行。
代码清单1-6演示了数组缓存技术。不必再在游标c1返回的每一行中执行查询来得到country_name,而是用一个名为l_country_names的关联数组来存储本例中的country_id和country_name键—值对。关联数组和索引类似,任意给定的值都可以通过一个键值来访问。
在执行查找式查询前,通过EXISTS操作对一个数组中是否存在一个匹配country_id键值的元素做一个存在性验证,如果数组中存在这么一个元素,那么country_name就从数组中获取而不需要执行查找式查询。如果没有这样的元素,那么就执行查找式查询,并且把查到的结果作为一个新元素存入数组。
你还需要理解,这种技术非常适用于不同的键值很少的语句,在本例中,当country_id列的唯一值个数越少时,查找式查询的执行次数可能也越少。如使用示例模式,执行查找式查询的次数最多是23,因为country_id列只有23个不同的值。
代码清单1-6 用关联数组实现的查找式查询
注意 关联数组所需内存是在数据库服务器中专用服务器进程的PGA(Program Global
Area,程序全局区)中分配的,如果数千个连接都要把程序的中间结果缓存到数组中,那么内存的占用将会大幅增加。你应当掌握每个进程的内存使用增加情况,并设计数据库服务器以适应内存的增长。
利用基于数组的技术也可在其他场景中消除不必要的工作。例如,可以通过把函数结果值存入关联数组来减少执行代价高昂的函数调用。1.5节讨论了减少执行次数的另一种技术。
注意 将函数结果存入一个关联数组仅适用于确定性函数。也就是说,这种函数对给定的输入集合,总是返回相同的输出。
1.4 对DUAL的过度访问
PLSQL代码中对DUAL表的过度访问情况并不罕见。应当避免对DUAL表的过度访问。因为从PLSQL中访问DUAL表会导致上下文切换,而这会损害性能。这一节总结了一些PLSQL程序中过度访问DUAL表的常见原因,并讨论了减少这种访问的方案。
1.4.1 日期的算术运算
在PLSQL中,没有理由通过访问DUAL表来执行算术运算或日期运算。因为大部分操作都能用PLSQL语言本身的结构完成。甚至SYSDATE也能脱离开SQL引擎直接用PLSQL访问。在代码清单1-7中加粗的SQL语句用于计算Unix新纪元时间(从1970年1月1日午夜到当前时间经历的秒数),使用了SELECT…from
DUAL语法。虽然访问DUAL表很快,但执行这个语句仍然会导致SQL和PLSQL引擎之间的上下文切换。
代码清单1-7 过度访问DUAL——算术运算
可以使用如下的PLSQL结构执行算术运算来避免对DUAL表的不必要访问。
完全不必调用SQL执行算术运算,简单地让PLSQL做这项工作,代码会更易读,也更高效。
过度访问当前日期或时间戳是增加DUAL表访问的另一个原因。考虑在一个SQL语句中直接调用SYSDATE而不是先用SELECT语句将SYSDATE保存到一个变量,然后再把这个变量传递给SQL引擎。如果需要访问刚刚插入的列值,那么用returning子句来取出该列值就能实现。如果你需要在PLSQL本身中访问SYSDATE,只需要用PLSQL结构将当前日期取出并赋给一个变量即可。
1.4.2 访问序列
对DUAL表进行不必要的访问的另一种原因,是要从一个序列中获得下一个值。代码清单1-8显示的代码片段通过访问DUAL表从cust_id_seq
序列中取出下一个值,并赋给一个变量,然后把这个变量的值插入customers表 。
代码清单1-8 过度访问DUAL——序列
更好的方法是不要将序列的值取出并存入变量,而是直接在INSERT语句本身中获得序列的值。下面的代码片段演示了INSERT语句怎么将序列产生的值插入customers表。用这种编码方法,就避免了对DUAL表的访问,因此也避免了引擎之间的上下文切换。
这个问题还有更好的解决办法:将整个PLSQL块改写为一个SQL语句。改写后的语句0.2秒就执行完了,而基于PLSQL循环处理的运行时间需要1.89秒。如下所示:
1.4.3 填充主—从行
另一个过度访问DUAL表的原因,是要把数据插入具有主从关系的几个表中。这种编码方法的典型例子是从序列中得到主表的主键值并赋给一个局部变量,再把这个局部变量插入主表和从表。这样做的原因是需要把主表的主键插入从表。
Oracle DataBase
9i引入了一项SQL新功能,它允许从插入的行中返回插入值,从而为这类问题提供了更好的解决方案。你可以用DML
RETURNING子句取得新插入主表行的键值,然后就能将这些键值插入从表。例如:
1.5 过多的函数调用
认识到一个设计良好的应用程序会用到函数、过程和包很重要。但本节不是讨论应该怎么使用模块化的方法编程,而是讨论在编程中如何避免不必要的函数调用。
1.5.1 不必要的函数调用
函数调用通常意味着将指令集的不同部分要装载到CPU。执行时需要从指令的一个部分跳转到另一个部分。这种跳转执行增加了性能问题,因为这引起了指令管道的大量转储(dump)和重新填充,结果是加重了CPU的负担。
通过避免不必要的函数执行,可以避免不必要的指令管道刷新和重新填充,这样就使得对CPU的需求降到最低。再次声明,我并不反对模块化编程,而只反对过度和不必要的函数调用。最好用例子来解释。
在代码清单1-9中,log_entry是一个调试函数,在每次合法性验证中都会调用它。但这个函数本身有一个对v_debug的检查,并且只有在调试标记设为“真”时才将消息插入。假设有个程序的循环中包括执行数百个这样复杂的业务合法值验证,那么实际上,即使v_debug标志的值设为“假”,log_entry函数也会被不必要地调用数百万次。
代码清单1-9 不必要的函数调用
PLSQL procedure successfully completed.
Elapsed: 00:00:00.54
代码清单1-9中的代码可以改写为仅当标志变量l_debug设为“真”时才调用log_entry函数。这个改写减少了不必要的log_entry函数执行。改写后的程序在0.
43秒内执行完成。如果执行次数更多,那么性能的提高会更明显。
如果还嫌不够好,可以考虑用条件编译结构来完全避免代码片段的执行。在代码清单1-10中,加粗的代码使用$IF-$THEN结构和条件变量$debug_on。如果条件变量$debug_on是“真”,那么代码块得到执行。在一个生产环境中,变量
$debug_on会设为“假”,这就消除了函数执行。注意,程序的执行时间进一步减少到了0.34秒。
代码清单1-10 用条件编译来避免不必要的函数调用
不必要的函数调用问题通常在从一个模板程序复制再修改的程序中频繁出现。观察程序,如果没必要调用某个函数,就不要调用它。
解释和本地编译的对比
PLSQL代码默认是解释执行的。在编译PLSQL的过程中,代码被转化为一种中间格式并存储在数据字典中。在执行时,引擎执行中间代码。
Oracle Database
9i引入了一项新功能:本地编译,即把PLSQL代码编译成机器指令并作为共享库存储。过度函数调用对本地编译的影响可能更小,因为现代编译器能够将子程序展开而避免指令的跳转。
1.5.2 代价高昂的函数调用
如果某个函数需要几秒的运行时间,那么在循环中调用此函数将导致代码的性能低劣。你应当优化频繁执行的函数以使它尽可能有效率地运行。
在代码清单1-11中,如果函数calculate_epoch在一个循环中被调用数百万次。即使每次执行此函数只耗费0.01秒,一百万次执行此函数也要耗费2.7小时。解决这个性能问题的办法之一是优化此函数使它执行一次只要几毫秒,不过这种深度的优化很难做到。
代码清单1-11 代价高昂的函数调用
另一个可选方案是把函数执行的结果预存起来,这样就避免了在查询语句中执行函数。可以用一个基于函数的索引做到这一点。代码清单1-12创建了一个基于calculate_epoch函数的索引。SQL语句的性能从1.39秒提高到了0.06秒。
代码清单1-12 用基于函数的索引代替执行代价高昂的函数调用
你应该明白基于函数的索引也是有代价的。INSERT语句和更新time_id列的UPDATE语句会导致调用函数和维护索引的开销。需要认真地权衡DML操作中的函数执行开销和SELECT语句中的函数执行开销,并选择一个开销较低的方法。
注意 从Oracle
Database11g开始,可以创建一个虚拟列,然后再在虚拟列上创建一个索引。虚拟列上索引的影响和基于函数的索引的影响是一样的。虚拟列优于基于函数的索引的优点是,你可以基于虚拟列对一个表进行分区,而这是基于函数的索引所做不到的。
另一种方法是利用从Oracle
Database11g开始提供的result_cache来优化代价高昂的函数调用。这种功能会将函数调用的结果记忆在一个实例的SGA所分配的结果缓存中。重复用同样的参数执行函数会从结果缓存中取值,而不需要重复执行函数。代码清单1-13显示的是利用函数result_cache功能来提高性能的例子。执行同样的SQL语句用了0.81秒。
代码清单1-13 带结果缓存的函数
总之,过度的函数执行导致性能问题。如果无法减少或消除函数执行,那么可以利用基于函数的索引或result_cache作为暂时的解决办法,从而将函数调用带来的影响降到最低。
1.6 数据库链接调用
过度使用数据库链接调用会影响应用程序的性能。在一个循环中通过数据库链接来访问远程表或修改远程表是一个不可扩展的方法。因为对远程表的每一次访问,都会导致本地数据库和数据库链接中包含的远程数据库之间的多个SQL*Net包的交换。如果数据库在地理上处于不同的数据中心,或者更糟糕一些,数据库是跨国的,那么等待SQL*Net的流量就会导致程序的性能问题。
在代码清单1-14中,游标每返回一行,远程数据库上的customer表都要被访问一次。我们假定一次网络往返需要0.1秒,那么100万次往返调用将需要大约27小时才能完成。而位于国内不同地区的数据库之间的响应时间为0.1秒是很常见的。
代码清单1-14 过度使用数据库链接调用
慎重地使用实体化视图能减少程序执行中的网络往返。在代码清单1-14的案例中,可以为远程customer表创建一个本地实体化视图。在程序执行前先刷新实体化视图,然后在程序中访问实体化视图,将表在本地实体化减少了SQL*Net往返调用次数。当然,作为应用程序的设计者,你需要比较实体化整个表和在循环中访问远程表的代价,选择最理想的解决方案。
另一种选择是将程序改写为使用远程表连接的SQL语句。Oracle数据库的查询优化器能优化这种语句,以减少SQL*Net往返的开销,而要使用这种技术,就需要重写程序,使这个SQL语句只执行一次,而不是循环执行。
调优代码清单1-14中程序的首选步骤是将数据实体化到本地或将代码改写为包含远程连接的SQL语句。不过,如果你无法做到这些,还有另外的解决办法。作为一个临时措施,你可以将程序转化为能够使用多进程架构。例如进程1处理1~100
000范围内的客户,进程2处理100 001~200
000之间的客户,等等。把这种逻辑应用到示例程序,创建10个并行执行进程,你就可以将程序的总运行时间减少到大约2.7小时。另一种可采取的方法是使用DBMS_PARALLEL_EXECUTE,将代码分解成多个任务并行处理。
1.7 过度使用触发器
尽管也能用Java语言来写触发器代码,但触发器通常还是用PLSQL编写。由于性能的原因,过度使用触发器是不理想的。数据库表中行的变化在SQL引擎中执行而触发器是在PLSQL引擎中执行,如果触发器频繁触发,程序就会遭遇到十分严重的上下文切换问题。
在一些情况下,触发器是无法避免的。例如,复杂业务中的合法性验证就不可避免要用到触发器。在这些情况下,你应当在合法性验证很复杂时才用PLSQL编写,而要避免滥用触发器进行简单的合法性验证。例如,用check约束而不是用一个触发器来验证列的值是否在合法值代码清单之内。
还有,应避免对一个触发事件使用多个触发器。不要为一个事件编写两个触发器,而应当把它们合并为一个,以使上下文切换的次数最小化。
1.8 过度提交
在PLSQL程序循环中经常见到插入、修改或删除每行后面紧接着就是提交。这种在每行后面提交的编码方法会导致程序执行得更慢。频繁的提交产生更多的重做(redo),需要日志写入器更频繁地将日志缓冲区的内容保存到日志文件。过度提交还会导致数据一致性问题,并且消耗更多的资源。虽然Oracle已经优化了PLSQL引擎以减少频繁提交的影响,但这无法替代由于自身编写良好从而减少了提交的代码。
你应当只在一项业务交易完成后提交,如果在到达业务交易的边界前就提交了,就会遇到数据一致性问题。如果必须用提交来提升中断后可重新开始的能力,那么建议使用批量提交。比起每行之后提交,每1000或5000行批量提交一次更好。每批的数量选择取决于应用程序。更少的提交会使程序的运行时间缩短。而且,从应用程序发出更少的提交也能提高数据库的性能。
1.9 过度解析
不要在PLSQL循环中使用动态SQL语句,因为这么做会引起过度解析问题。反之,应通过使用绑定变量来减少硬解析的次数。
在代码清单1-15中,从游标c1取得cust_id,然后根据cust_id访问customers表,来获取客户的详细信息。构造出一个包含字面值的SQL语句,然后用本地动态SQL的EXECUTE
IMMEDIATE结构来执行。问题在于每从游标c1取出一个不重复的cust_id值,就会构造一个新的SQL语句,然后将它发送到SQL引擎去执行。
执行共享池中不存在的SQL语句,就会触发一次硬解析。过度硬解析会对库缓存(library
cache)产生压力,因而降低了应用程序的可扩展性和并发执行能力。当游标c1返回的行数增加时,硬解析的次数会线性增长。这个程序也许可以在只有少量行需要处理的开发数据库中正常运行,但用这个方法在生产环境运行就会很成问题。
代码清单1-15 过度解析
应当尽可能减少硬解析。在循环中执行动态SQL将增加硬解析的影响,如果并发执行增多,这种影响就会放大。
1.10 小结
本章介绍了多个不适合使用PLSQL的场景。请牢记,SQL是一种集合语言,而PLSQL是过程性语言。在设计程序时,可以考虑下列建议。
用SQL解决查询问题。用集合的方式进行思考,用SQL写的查询,比起用嵌套循环逐行处理的方式执行查询的PLSQL程序更加易于调优。
如果必须用PLSQL来编写代码,请尝试尽可能将较多的工作负担交给SQL引擎。这种技术随着Exadata等新技术的出现而变得更重要。Exadata数据库机中的智能扫描设备能将工作负担交给存储节点,从而提高用SQL编写的程序性能。而PLSQL结构不能从Exadata数据库机获得同样的好处,至少在11gR2中是不能的。
如果必须使用循环,那么使用PLSQL提供的批量处理功能。利用本章介绍的技术减少在PLSQL中的不必要工作,比如不必要的函数执行或者对DUAL表的过度访问。
只把使用单行、基于循环的处理作为最后的手段。
没错,用PLSQL处理所有的数据和业务,用Java或其他语言来展现界面和进行用户合法性验证。利用本章描述的方法可以编写出高度可扩展的PLSQL语言程序。
|
|