Database 类别下的文章

HadoopDB

首先思考一个问题:针对弱关系型数据的数据仓库解决方案会是怎样的?

耶鲁大学的这个 HadoopDB 研究项目挺有意思。这是个并行 DBMS(PostgreSQL) 技术和 MapReduce 的结合的产物。

HadoopDB_Arch.jpg
(上图来源)

上图中的 SMS 是 "SQL to MapReduce to SQL" 的缩写。这是 HadoopDB 的一个设计难点。经过了两层转换,对于 SQL 执行的效率多少会是个问题。

也可以对比一下 Facebook 的 Hive :

HiveDB.jpg

说起 DBMS 和 MapReduce 结合,自然要提起 GreenPlum, 原来是 Hadoop 的间接竞争对手,现在变成直接的了。相比来说,GreenPlum 要更成熟一些。HadoopDB 毕竟是学院派的东西。

GreenPlum_GPDB_Arch.jpg

二者都是典型的 Share-Nothing 结构。类似 Oracle 集群的 Share-Storage 的模式现在已经有点过时了。更多混搭出来的技术解决方案让人喜忧参半,喜的是有很多东西可以选择,忧的是你不知道哪个项目生命期更长久。

--EOF--

OakTable Network本身就是一群喜欢相互讨论并和有类似想法的朋友交往的人。更确切地说,是一群致力于对Oracle数据库技术进行科学探讨并爱追根究底的家伙。

这一切都始于1998年的某个时候,那时一帮Oracle专家,包括Anjo KolkCary MillsapJames Morle和其他一大群朋友开始每年以各种借口进行一到两次聚会。每个人都会带来一瓶苏格兰或波本威士忌,作为回报他们也赢得了在我家里某些地方打地铺的权利。

大部分时间我们围着餐桌闲坐,周围布满了电脑、网线、纸和其他一些东西,讨论Oracle,聊聊趣事,使用数据库领域新的并且更优异的方法做实验。在2002年的春天,所有条件更加成熟。一天夜里,我意识到我有16位世界知名的Oracle科学家闲坐在我的餐桌旁。我们三四个人挤在一个房间睡觉,甚至不得不在早上借邻居的淋浴。Anjo Kolk建议我们把自己叫做"OakTable Network"(名字来源于我的餐桌),大约两分钟以后,我们注册了域名http://www.OakTable.net

James Morle 现在和他的妻子Elain一起维护这个网站,虽然或许网站没有像预期的那样保持经常更新,但至少可以用来提供链接、名字等等,这就挺有用了。我们经常在上面进行问答挑战。

挑战是我们在讨论过程中偶尔发生的事情。询问我们任何关于Oracle的技术问题,如果我们不能在24小时内提供答案(不管是对,错或解决办法),提问者都将得到一件T恤,代表他(或她)打败了OakTable。

这个挑战,尽管有时没有像我们想要的那样进行,也许是因为它看起来好像是我们喜欢被自己回答不上的问题挑战。不过它的反面却是真实的,那就是我们的目的是解答任何人的疑问,不管这些问题看上去是多么的"简单"或是"容易"。

注:这是 Mogens NørgaardTroubleshooting Oracle Performance 一书前言中介绍 OakTable 技术组织的来龙去脉。OakTable 是 Oracle 数据库领域最有趣的一个技术组织,他们以运用科学方法(以及科学团体的伦理)从事所有活动。其成员都是顶尖的技术高手,现有大约70位成员,遗憾的是,或许因为语言的隔阂,还没看到来自中国的成员。Ooops , 前言真的不好翻译...

--EOF--

阿里巴巴 DBA 团队 简朝阳的大作《MySQL性能调优与架构设计》已经开始正式上市。我刚认识朝阳同学的时候,他还刚刚毕业,短短两三年后,已经能够独当一面,应该说阿里 DBA 团队是个很锻炼人的地方,当然重要的是他的刻苦钻研的劲头儿。早早就看过他的初稿,这本书是他倾力之作,有理由大力推荐。下文是我前一段时间写的推荐序。

拥抱MySQL数据库技术

MySQL_Tuning.jpg时至今日,恐怕已经没有人再把 MySQL 当成一个玩具性质的软件产品,即使是数据库市场执牛耳者如Oracle公司也不得不正式面对来自MySQL的冲击。如果说几年前,还有人对使用MySQL 有所疑虑么? 经过几年来互联网的高速发展,无数大型网站用其成功案例证明,以MySQL为基础的数据层解决方案已经成为互联网应用不可或缺的一个重要组成部分。

当下也是数据库技术应用处于激烈变革的时期。这并不是说传统的关系数据库技术在这两年有了多大的新突破,而是用户的需求在迅速变化。更多时候,用户不再需要单一的软件产品,而是灵活、高效、可靠、可控、低廉的解决方案。很多大型站点甚至根据自己的需求来改进 MySQL,进而回馈给开源社区,这也是开放的魅力所在,对于传统的商业数据库软件商来说,这是不可想象的事情。

MySQL早已不再是单一的数据库软件,以其为基础发展起来的各种开源组件令人目不暇接,而用这些组件构成的解决方案也是层出不穷。如何能够把以 MySQL为核心的这一系列软件充分运用,构建大型可扩展性网站,正是不少LAMP架构体系的网站开发者乃至架构师一直关心的问题。现在中文图书市场上 MySQL相关的书籍并不在少数,但放眼看去,绝大多数是教程类的内容,这本《MySQL性能调优与架构设计》则主要着眼于性能架构这两个当下大家更为关注的话题,结合作者几年来的实战经验与研究心得,相信能让不少网站少走弯路。

期待这本书让更多人受益。如果读者朋友们也能把自己的心得分享出来,那是再好不过的事情了。经常有即将毕业的学生以及网络上的朋友给我发来邮件,表示对数据库技术有兴趣,但是不知道如何切入,我的建议是,从学习MySQL开始吧!

--EOF--

《程序员》杂志 100 期约稿的稿件。这样比较"大"的话题我写起来并非顺手,而且只是从一个人所见的角度开写,难免贻笑方家。有所遗漏或者有失偏颇,拍砖即可。



2001 年对我自己来说,是一个比较重要的时间点--正式踏上工作岗位,也在这一年奠定了以后工作的技术方向。在 2001年,《程序员》杂志经过两期试刊后也已正式创刊。转眼间,杂志即将出版第 100 期,让人心生感慨。自己几年来持续关注数据库技术领域,《程序员》是一份很重要的参考信息来源。这里回顾一下自《程序员》创刊以来的数据库大事,算是一份纪念,或有谬误,敬请指正。


2001

就从 2001 年说起吧, 2001年6月的ORACLE OpenWorld大会中,ORACLE发布了ORACLE 9i。相比上一个主要版本,也就是 Oracle 8i来说,最大的新产品特性就是真实应用集群(Real Application Clusters, RAC)了。ORACLE 9i的RAC在TPC-C的基准测试中打破了数项记录,一时间业内瞩目。刚在上一年发布 SQL Server 2000 的微软在这一年产品上没什么更大的动作,正在积极拼抢市场。而 MySQL 在 1月份发布了 3.23 产品版,给不少开源爱好者以欣喜。

DB2 在这一年产品上没什么亮点,但是以 10 亿美金收购了 Informix 的数据库的事情震动业界。记得自己当时正好有个 Informix 项目要实施,着实看了几天 Informix 技术文档。这一年国内数据库领域的一件值得一提的小事是 ITpub.net 的创建,这个当初看似不起眼的论坛,在随后的几年中涌现出了一大批数据库技术人才,很大程度上在国内普及了 Oracle 数据库技术。


2002

IBM 推出DB2数据库V8.1的测试版,估计是还在消化 Infomix 的客户资源,几个月之后正式版才能面试。而 Oracle 与 Sun 庆祝了 20 年的合作伙伴关系。之后,Sun 不复 .com 大潮中的明星范儿,Oracle 因为全力支持 Linux 也与 Sun关系愈加微妙。Oracle Open World 第一次在国内举行,地点是北京,会议规格不低,Larry Ellison 在会上进行了主题演讲,此前,这位软件界的传奇人物已经来过中国数次了。[喜欢IT八卦的人可以搜索一下《IT江湖水也深》这篇文章。]

微软连续第二年没有对 SQL Server 发布新版本。

MySQL 发布 4.0 Beta 版。从 4.0 开始,InnoDB 正式成为 MySQL 的默认引擎。在 InnoDB 的基础上,MYSQL对于事务的处理能力有了极大提升。


2003

SQL:2003 发布。这个版本针对 SQL:99 的一些问题进行了改进,支持 XML,支持 Window 函数、Merge 语句等。随着,会看到各大数据库厂商纷纷宣布新的版本中对该标准的支持,这是他们一贯的姿态。

MySQL 4.0 正式发布。在全文索引、嵌入式应用方面得到增强。这个时候的 MySQL 仍然缺乏一些企业级数据库的关键功能。

Oracle 这一年发布了 Oracle 10g, g 代表 Grid ,网格计算。这一年中"网格计算"火爆程度不亚于现在的"云计算",随后的几年,这个网格计算基本上还只存在于专家们的嘴里。所以,去年 Larry Ellison 在会议上对"云计算"表示不屑也是正常之举。在这一年,Oracle 也宣布针对Linux 64位环境的产品准备就绪,接下来的一年里,Oracle 宣称雇佣了近万人的 Linux 相关的开发人员,可谓不惜血本,当然,这些投入在日后得到了超值回报。从技术的角度上看,其贡献也是有目共睹的,在 I/O 能力、进程扩展能力上都作出很大贡献。

雅虎技术人何伟平的一篇《PostgreSQL 昨天,今天和明天》对于 PostgreSQL 的普及起到了很大作用。


2004

Danga Interactive 针对 LiveJournal.com 开发的Memcached 经过上一年的高频度发布,在这一年只发布了一个版本,标志着已经进入相对稳定阶段,只可惜养在深闺人未必识。关注者并不多。以此为滥觞,伴随着Web 2.0 的火热,类似的分布式对象缓存系统层出不穷,到现在已经成了各大网站标准配备。Memcached 的出现对于数据库方面相关应用设计也带来了更多思路。

这一年嵌入式数据库 SQLite 迎来了较大发展,版本3 完成开发并发布了稳定版。 这些努力为 SQLLite 获得 2005 Open Source Award 打下很好的基础。

我自己第一次给技术杂志投稿《书写历史的甲骨文》,当然是发在《程序员》。


2005

PostgreSQL 8.0 的发布宣告正式开始支持 Windows 平台,成为真正意义上的 Windows 平台数据库(Native Server)。这是 PostgreSQL 发展史上相当重要的一件大事。

微软时隔五年,终于发布了 SQL Server 新版,是为 SQL Server 2005。最大亮点在于对 XML 数据的支持,当时不少技术媒体对此都颇为关注。IBM 发布 DB2 V8.2。

Oracle发布了Oracle10g R2 版本,10g 的 R1 版本稳定性广为诟病,R2版本质量有很大增强,一部分用户终于可以放心一点从 9i 升级到 10g。10月,Oracle 抄了MySQL 后路,将 InnoDB 收归帐下。几年过去回头看,Oracle 此举对 MySQL 影响太大,直到现在,MySQL 也没能自己拥有一个超越 InnoDB 的存储引擎,当然,也不可能超出 InnoDB 的在线备份功能。历史不容假设,否则的话,或许 MySQL 最后仍将独立发展也说不定。 MySQL 在这一年发布5.0 Beta版,引入数个新特性,比如存储过程、触发器等,而这些其实是其他主流商业数据库早已实现的功能,从这个角度上看,MySQL和其竞争对手比较,仍然是追赶者,甚至也落后于开源兄弟 PostgreSQL。


2006

IBM 在这一年发布了DB2 V9 ,最大特性是加入了 PureXML 支持。IBM 对 XML 方面寄予厚望,不过时间证明,XML 对于数据库市场的影响并没有那么大。

在嵌入式数据库方面,Oracle 收购 Berkeley DB 的母公司 Sleepycat Software。到此,MySQL 两个最重要的存储引擎都控制在 Oracle 手里(Falcon 引擎开发进度遥遥无期,最后不了了之),尽管现在来看关系并未僵化,但谁也说不好未来能怎样。Oracle也宣布推出Enterprise Linux,进军操作系统市场,开始和 Linux 厂商之间展开竞争又合作的关系。

SQL:2006发布,继续增强 XML方面的特性。Ingres,这个早期数据库流派的标识产品,以GPL版权形式开放代码。


2007

Oracle 发布 11g 数据库,引入物理 Data Guard 算是最大新功能。MySQL 的拥趸者要偷笑,其实 MySQL 的 Slave DB早就可以在恢复的同时提供查询的能力了。MySQL 宣布将对 5.0 提供两个变种,社区服务器(Community Server)与企业服务器(Enterprise Server),后者发布周期为1月一次,而社区服务器发布周期则不固定。

随着 Firefox 的发行量增加,其内嵌的SQLite 也赢得了大量部署用户。如果单纯从部署数量来看,SQLite 倒也堪称最流行的DB。


2008

2008年数据库领域的最大的事件,是 Sun 收购 MySQL,价格 10 亿美元。一年多时间过去,回头来看,这次收购对于 MySQL 不是什么好事情。年尾,MySQL 发布 5.1 生产版,质量并不好,引起了不小争议。在这个版本中正式提供对分区(Partition)功能的支持。此外,在这一年中,开源社区对于 给MySQL 贡献的补丁和各种解决方案让人眼花缭乱,是可喜之事。Google 和 Facebook 等大站都对 MySQL 作出不小的贡献。

微软发布 SQL Server 2008,没有提供什么更扎眼的功能。其实关系数据库发展到现在,要想作出更大革新已经是几乎不可能的事情了。对于微软来说,Windows平台上 SQL Server 有其压倒性优势,可时过境迁,一方面的优势演变成了其他平台上的劣势。

PostgreSQL 8.3 发布,应该说从2008年开始,PostgreSQL 在市场上表现已经不容小视,以其为基础的集群BI系统 GreenPlum 已经引起了国内不少用户的关注。

SQL 标准SQL:2008 发布。从SQL:99 到 SQL:2009,可以看到标准修订的周期越来越短,多少也反映了对技术的需求之快。


2009

到现在为止,这篇文章还缺席 Sybase 的信息。必须要提一下的是,Sybase 将在3月份公布其列数据库(Column-based Database)的新版本:Sybase IQ 15 。说起来,Sybase 也是传统数据库厂商中唯一提供列数据库的公司。

此外,在云计算应用下涌现出的非关系型数据库(主要是Key/Value存储)产品渐欲迷人眼,有人在疑惑关系数据库已到末日。"关系数据库已死" 每隔几年就会有人跳出来喊,对关系型数据库(RDBMS)来说,百足之虫,死而不僵。


不是总结的总结

以上只是软件行业发展过程中的一个小小的阶段。如果要做点总结的话,我觉得这几年的值得探讨的一个地方就是 MySQL 的发展模式,从最初的近乎玩具的软件到现在对业界举足轻重的产品,其发展途径值得我们深思。反观国内,我们也有一些所谓的国产数据库,投入重金,多半昙花一现,恐怕技术因素不是主要问题吧?


补充1) 应该说,时间就是善于和人开玩笑。这篇文章写完不久,就传来 Sun 被 Oracle 收购的消息。尽管现在还不能断定收购一定能完成,但这毕竟宣告了有关数据库技术的一个转折点。现在无从判断 MySQL 究竟发展方向如何,也或许,MySQL 的命运掌握在广大用户的手中。

补充2) 其实我非常想写一下"国产数据库",但出于某种原因考虑,还是放弃了。长期以来,那似乎是和我接触的数据库圈子并行的一个轨道。想来想去,还是不要徒增烦恼了吧。

补充3) 这是个变革的时代,新的数据库产品层出不穷。"乱花渐欲迷人眼"。

补充4) 这篇文章和我参与翻译的 Troubleshooting Oracle Performance 一书,似乎可以用来小声的宣布一件事,那就是我关注的技术领域重心早已不再是数据库了。再见,Database !


--EOF--

继续贴出 Troubleshooting Oracle Performance 一书第十二章《优化物理设计》的翻译稿的部分节录。最近真是筋疲力竭。翻译不止是考验技术水平、英文水平、中文驾驭能力,还有耐心和信心。

TOP.jpg
(此书中文名字还未敲定,要不大家帮着命名一下?)



段头块的争用

每个表和索引段都会有一个头数据块(header block)。这个数据块包含以下元数据:关于这个段的高水位(highwatermark)的信息,组成这个段的区间(extent)的列表以及关于空闲空间的信息。为了管理空闲空间,根据使用的段空间管理方式的不同,头数据块会含有一个空闲列表(freelist)或者一组包含自动段空间管理(automatic segment space management)的信息的数据块。比较典型的情况是,段头数据块在多个进程并发地修改其内容时会发生争用。注意,头数据块在以下几种情形下将会发生修改:

  • 插入语句使得有必要提高高水位
  • 插入语句使得有必要分配新的区间
  • 删除、插入或更新语句使得有必要修改空闲列表

解决这些问题的一个可能思路是,对这个段进行分区以将压力分布到多个段头块上去。虽然有时候根据负载以及分区键值(partition key)其它的分区方式也可以实现,但是在大部分时候,可以通过散列分区实现这一点。然而,如果是由于第二或第三种情形导致这个问题,还可以使用其它的解决办法。对于第二种情形,可以使用更大的区间(extent)来解决。这样,新的区间分配将很少发生。对于第三种情形,空闲队列(freelist)可以被空闲队列组(freelist group)移动到其它数据块,这对于使用自动段空间管理模式(automatic segment space management)的表空间不适合。事实上,在使用多个空闲列表组的时候,空闲列表就不再被存储在段头数据块(segment header block)中了(它们被分布到与参数FREELIST GROUPS数量一致的数据块中,这样在它们上面的争用将减少,而不仅仅是将争用移往别处而已)。另一个可能是使用自动段空间管理的表空间而不是空闲列表段空间管理的表空间。

注意:长期存在一个关于Oracle数据库引擎的神话是,空闲列表组只有在使用RAC(Real Application Cluster)的时候才是有用的。大谬。空闲列表组在任何数据库中都是有用的。之所以特别强调这一点是因为我看到听到这种错误信息太多次了。


其实我一直想尝试用一点比较新的语言,比如最后一句,用"这种事儿我都听过N次了",效果可能更好。但,还是放弃了。

--EOF--

继续贴出 Troubleshooting Oracle Performance 一书第五章《配置查询优化器》的翻译稿的部分节录。本章初稿译者胡怡文.

配置还是不配置

在此套用一句肯尼亚谚语 ,"配置查询优化器的代价是昂贵的,但值得为此付出。"(注1)实际上,我曾见过许多低估良好配置重要性的站点。有时,我甚至和一些人进行激烈的讨论,他们认为"没有必要费心为每一个数据库单独配置查询优化器,我们已经有一套初始化参数,而且在所有数据库上屡试不爽。"通常,我首先会这样回答这个问题:"如果一个配置集能适用于所有数据库,为什么Oracle要介绍二十多个专用于查询优化器的初始化参数?甲骨文公司知道自己在干什么。如果存在这样一个万能的神奇配置,他们会以默认的方式提供,还可以省去一大堆初始化参数的正式说明文档。"接下来我会详细解释这个神奇配置不存在的原因:

  • 每个应用都有自身的需求和负载概要,并且
  • 每一个由不同的软硬件构成的系统,都有其自身的特点。

如果遇到麻烦的是顾客,通常我也会提醒他们"您找我是因为你遇到性能上的问题,对吧?由于某种原因,应用没有达到最佳表现,但数据库也得为目前的情况负一部分责任...所以,让我们着手处理这个问题吧。"

据说,至少从Oracle9iR2开始,查询优化器就能良好运转了,这意味着它能够为大多数注2SQL语句生成高效的执行计划。然而更准确的说,仅在查询优化器配置正确且数据库的设计能够发挥其所有特性时才是如此。这件事我已再三强调,同时也要记住查询优化器的配置不仅包括初始化参数的设置,也包括系统统计和对象统计。

配置路线图

既然没有这样的神奇配置,就需要一个可靠的步骤来帮助我们。图5-1汇总了我采用的主要步骤。

CBO_Configure.png

图5-1. 配置路线图的主要步骤

下面是对图中标有数字的步骤的描述

  • 1. 总是需要调整的两个初始化参数:optimizer_mode和db_file_multiblock_read_count。 就如你将在本章后面看到的那样,后者对查询优化器本身来说已经不再那么重要。然而,个别操作的性能还将严重依赖它。
  • 2. 这步要调整的几个初始化参数通常默认已经被设置为比较合适的值,所以这步显得不是十分重要。然而无论如何,这一步的目的是要启用或禁用查询优化器的某些特性。
  • 3. 既然系统统计和对象统计为查询优化器提供了至关重要的信息,那么它们必须被收集。
  • 4. 根据初始化参数workarea_size_policy的不同,在内存中存储数据时选择是手动还是自动调整内存的使用量。做出选择后,其它初始化参数值在第五步或第六步设置。
  • 5. 如果上面选择的是自动设置工作使用的内存量,那么需要设置初始化参数pga_aggregate_target。
  • 6. 如果选择手工设置的话,实际使用的内存量分别取决于对每一种不同操作所设置的阀值。基本上,对每一种不同的操作都要设置一个特殊的初始化参数。
  • 7. 当刚才的设置生效后,就开始测试应用。在测试期间,对没有表现出期望性能的那部分收集执行计划。通过分析执行计划,你应该能够推测出问题所在。本阶段需要注意,关键是要识别出一般的、非特殊的现象。比如说,需要注意查询优化器是否使用了过多或过少的索引,又或是否没有正确识别约束。
  • 8. 如果查询优化器能够为大多数SQL语句提供高效的执行计划,说明配置成功。否则,需要进行第九步。
  • 9. 假如查询优化器倾向于使用过多或过少的索引,又或是嵌套循环的话。通常需要调整初始化参数optimizer_index_caching和optimizer_index_cost_adj修正这个问题。如果查询优化器错误地估计了基数(cardinality)。有可能是某些直方图丢失或需要调整。在Oracle 11g中,扩展的统计(extended statistic)也能够提供一些帮助。

根据图5-1,从第1步到第6步设置的初始化参数不宜改变。当然,这也不是铁板钉钉的。如果在第九步调节了索引相关的初始化参数和直方图后,还没有达到预期的效果。就有必要从头再来了。还有一点要提一下,既然有些初始化参数的设置对系统统计有影响,在调整它们以后,必须重新计算一下系统统计值。


  • 注1:那句肯尼亚谚语是"和平的代价是昂贵的,但值得为此付出。" 可以在http://www.quotationspage.com/quote/38863.html. 找到这个引用。
  • 注2:和我们在其它可想像的活动中一样,在软件开发中完美也是不可信任的。即使你和Oracle都不希望这样,查询优化器也是如此。因此,应当期盼只有少数的SQL语句需要手动调整的介入(这个话题放在第七章)。
--EOF--

继续贴出 Troubleshooting Oracle Performance 一书第四章《系统和对象统计信息》的翻译稿的部分节录。在前面几章的部分章节放出来后,收到了很多朋友的意见和建议,在此一并谢过!翻译更多是考量译者的中文水平,现在我们几位译者对此是深有体会。本章初稿译者朱一(@mujiang)



保持统计信息时效性的策略(Strategies for Keeping Object Statistics Up-to-Date)

工具包dbms_stats提供了很多管理对象统计信息的功能。那么我们该如何使用它来达到最佳配置呢?这个问题很难回答。很可能就没有确定的答案。就是说,没有一种方式适用于所有情况。让我们研究一下该如何着手解决这个问题。

基本准则是,或许是最重要的一个,查询优化器需要通过对象统计信息知道数据在数据库里面是如何存储的。因此,修改数据以后,同样需要刷新对象统计信息。我提倡定期收集统计信息。反对者的理由是数据库运行好好的,没必要重新收集统计信息。这种策略引起的常见问题是,一些对象统计信息依赖于实际存储的数据值,比如修改了最大/最小值,这样的修改不会经常发生在一些典型的表里面,但是这些数据改变是危险的,它们被应用程序频繁的使用(引用过时的统计信息)。实践当中,太多的问题是因为对象统计信息过时引起的。

显而易见,反复收集静态数据的对象统计信息是没有意义的。只应该对统计信息陈旧的对象进行收集。所以,需要利用好每张表的修改次数的统计记录。这样,我们只需要收集哪些数据发生了显著变化的表的统计信息。默认情况下,当一个表里面有超过10%的行被修改后,就认为它的统计信息是过时的(陈旧的)。缺省值就不错,在Oracle 11g以后,这个缺省值可以修改。

收集统计信息的频率也值得探讨。从每个小时收集到每个月,或是更少,均看到过成功案例。其实这个真的依赖于数据。当用并不陈旧的表统计信息作为基准时,太长的时间间隔引起过多表的统计信息陈旧,就要花更多的时间收集统计信息。因此我喜欢收集得稍微频繁一些,分散负载,尽量缩短每次收集任务的时间。如果你的系统每天或每周有一些时段负荷比较低,就在这些时段运行计划的收集作业。如果你的系统是真正的7x24的系统,最好频繁的运行收集任务(注),每天运行多次,尽量多分散负载。

如果有好的理由不需要收集一些表的统计信息,在Oracle 10g以后,可以锁定对象统计信息。计划收集作业就会跳过这些对象。这样远远好于禁止收集整个数据库的统计信息。遗憾的是,在Oracle 9i中不能锁定对象统计信息,变通方法是,利用表的监控属性,禁止这些不需要收集统计信息的表的监控,收集模式(schema)或者数据库的统计信息的作业就会跳过这些表。

如果你有批处理任务一次加载、修改很多数据,干脆不要等待调度任务来收集这些对象的统计。直接将对这些对象的收集统计任务加到批处理任务的最后面。也就是说。如果你知道一些表的数据会被大量修改。修改完数据后,立刻收集对象统计信息。

从Oracle 10g开始,应该尽可能的利用默认的收集作业。为满足需求,应该进行检查默认的配置,如果必要的话,进行必要的变更。既然只有Oracle 11g以后可以在对象级别配置收集任务,你可以在缺省收集作业之前运行自定义的作业以收集一些有特殊需求的表的统计信息。这样,缺省收集作业仅操作统计信息过时的表,跳过有特殊需求的表。锁定特性也可以确保只有特定的收集作业才可以重新收集那些关键表的统计信息。

如果收集统计信息导致了低效的执行计划,有两个办法。一是恢复以前合适的统计信息来修复问题。二是诊断查询优化器为何使用新收集的统计信息得出了低效的执行计划。首先要检查统计信息是否正确的描述了数据的分布。比如,采样新的数据分布得到了不同的直方图。有可能是收集本身,或者是收集用到的一个参数的问题,导致了坏的统计信息。如果统计信息是可信的,有两种可能导致低效的执行计划:错误的配置了查询优化器,或者优化器犯了一个错误。对于后者我们无能为力,而对于前者,我们能找到解决办法。无论如何,你应该避免仓促的下结论,推断说是收集统计信息引起的问题,进而停止收集统计信息。

最佳实践是使用工具包dbms_stats收集对象统计信息。然而,有些情况下,正确的对象统计信息反而误导查询优化器。有一个常见的案例,比如历史数据必须保留很长一段时间(比如有些类型的数据在瑞士必须保留十年),如果随着时间的推移,数据分布基本不变,用工具包dbms_stats收集对象统计信息会运行良好。相反,如果每个时期有不同的数据分布,应用程序仅仅使用全部数据的一个子集,那么手工修改统计信息使它反映最相关的数据就是明智之举。换句话说,如果你知道工具包dbms_stats忽略了或者不能发现最相关的数据分布,告诉查询优化器回避对象统计信息就是恰当的。


注:对此,译者有不同的观点。对于比较繁忙的在线系统,数据变化可能频繁,但数据特征的变化未必频繁。不管如何,频繁收集统计与否,DBA 必需熟知两种可能带来的影响。(译者注)

--EOF--

九十年前的今天,是个特殊的日子。

TOP 第二章 之 绑定变量

继续贴出 Troubleshooting Oracle Performance 一书第二章《关键概念》的翻译稿的部分节录。昨天贴出第一章的部分内容,收到不少朋友的反馈,坦诚的讲,第一章多半是通用知识,和 DB 相关的信息并不是很多,这次再看看第二章的(借口归借口,问题还是要改正)。必须要说明的是,此书翻译并非兄弟我一人之力。译者包括:童家旺、胡怡文、冯大辉(出版顺序),还有海外华人朱一和青年才俊张磊两位的劳动成果。如果留言有问题,请在 Twitter 上给我反馈也可: @Fenng

TOP.jpg
(此书中文名字还未敲定)



绑定变量

绑定变量通过两种方式来影响应用。第一,从开发的角度看,它使得开发或者变得简单,或者是变得更加困难(或更精确地讲,需要更多或更少地编码)。既然这样,具体的效果就取决于用来执行SQL语句的应用程序接口(Application Programming Interface, API)。例如,如果是使用PL/SQL来编码,使用绑定变量来执行就会更加简单。另一方面,如果是使用JDBC(Java Data Base Connectivity)来开发,不使用绑定变量来执行SQL语句则会更加简单。第二,从性能的角度看,绑定变量既有优势也有劣势。

注意:你将会在下面的内容中看到一些执行计划。第6章将会介绍如何获取并解释执行计划。如果有什么不清楚的话,可以考虑稍后返回本章。

2.5.1 优势

绑定变量的优势是可以在库缓存中共享游标,这样就可以避免硬解析以及与之相关的额外开销。下面内容是运行脚本bind_variables.sql的结果,它展示了三个INSERT语句由于使用绑定变量而共享了库缓存中的同一个游标的情形。

SQL代码, 略.

可是,也有一些情况下,即使使用绑定变量也会产生多个子游标。下面的例子就展示了这种情况。注意,INSERT语句与前面例子中的完全一样。只有对应的VARCHAR2变量的最大长度发生了变化(从32变成33了)。

SQL代码, 略.

之所以会创建新的子游标(子游标1),是因为相对于最初的3个INSERT语句来讲,第4个INSERT语句的执行环境发生了变化。 这个不匹配可以通过查询视图 v$sql_shared_cursor 来得到确认,是绑定变量的原因。

SQL代码, 略.

这是由于数据库引擎应用了绑定变量分级(graduation)。这个功能的目的是为了最小化子游标的数量,它是根据绑定变量的长短将绑定变量(各个大小不同)分为四个级别。在32个字节以内被分在第一个级别,33到128个字节的被分在第二个级别,129到2000个字节的被分在第三个级别,其余的大于2000个字节的被分在第四个级别。NUMBER类型的绑定变量被分在它的最大长度22个字节上的级别上。从下面的例子可以看到,视图v$sql_bind_metadata显示了级别的最大长度。注意,即使在子游标1的变量长度只有33的时候,也是使用最大长度为128的级别。

SQL代码, 略.

系统不要求每次生成子游标的时候都生成一个新的执行计划。新的执行计划是否与另一个子游标使用的执行计划一致,也依赖于绑定变量的值。这将在下面的内容中进行介绍。

2.5.2 劣势

在WHERE从句中使用绑定变量的缺点是会有一些至关重要的信息对查询优化器不可见。事实上,对查询优化器来讲,使用直接文本要比使用绑定变量来的更好。使用直接文本可以提高成本估算的准确性。当检查一个值是否在可用数值范围以外(也就是,小于存储在这个字段的最小值,或者大于最大值)或者是否利用到直方图(histogram)时,就更是这样了。为了展示的需要,我们准备了一个含有1000条记录的表,它的字段id的值在1(最小值)到1000(最大值)之间。

SQL代码, 略.

如果一个用户查询id小于990的所有记录,查询优化器知道(根据对象的统计信息)有差不多99%的记录被筛选。因此,它会选择使用基于全表扫描的执行计划。同时请注意,估算出的基数(执行计划中Rows字段的信息)与查询语句实际返回的记录数是否相符。

SQL代码, 略.

当另外一个用户查询id小于10的所有记录时,查询优化器知道只有大约1%的记录会被选中。因此,它会选择使用基于索引扫描的执行计划。在这个例子中,也请注意估算的准确与否。

SQL代码, 略.

只要是使用到绑定变量,查询优化器都会忽略它们的具体值。从而,前面例子中的准确的估算就不太可能会出现。为了解决这个问题,Oracle9i中引入了一个被称为绑定变量窥测(bind variable peeking)的功能。

警告:绑定变量窥测不支持随Oracle9i一起发布的JDBC 瘦驱动(JDBC thin driver)。这个限制在Metalink的注解273635.1中有记载。

绑定变量窥测的概念是比较简单的。在物理优化阶段,查询优化器会窥测绑定变量的值,将它作为文本来使用。这种方法的问题是它生成的执行计划会依赖第一次生成执行计划时所提供的值。下面这个基于脚本bind_variable_peeking.sql的例子展示了这种情形。注意,第一次优化是使用值990来执行的。结果,查询优化器就选择了全表扫描。由于游标是共享的,因此是这个选择影响了第二次使用10作为条件的查询语句。

当然,如同在下面的例子中那样,如果第一个执行计划替换成使用值10来执行,查询优化器就会选择一个基于索引扫描的执行计划-然后,就会再一次发生这两条查询语句上。注意,为了避免共享前面例子中的游标,这些语句是使用小写字母来写的。

有必要强调,只要游标还保存在库缓存中并且可以被共享,就可以被重用。不管与它相关的执行计划的效率如何,这种事情都会发生。

为了解决这个问题,Oracle11g中引入了一个称为扩展的游标共享(extended cursor sharing,也称为适应性游标共享,adaptive cursor sharing)的新功能。它的目的是在重用一个已经存在的但是会导致执行效率低下的游标时能够自动进行识别。通过查看前面例子中使用的SQL语句在v$sql中的内容,可用来帮助我们理解这个特性是如何工作的。要到Oracle11g中v$sql视图中才有下面这些字段:

  • 是否绑定敏感(is_bind_sensitive):不仅指出是否使用绑定变量窥测来生成执行计划,而且指出这个执行计划是否依赖于窥测到的值。如果是,这个字段会被设置为Y,否则会被设置为N。
  • 是否绑定可知(is_bind_aware):表明游标是否使用了扩展的游标共享。如果是,这个字段会被设置为Y,如果不是,这个字段会被设置为N。如果是设置为N,这个游标将被废弃,不再可用。
  • 是否可共享(is_shareable):表明游标能否被共享。如果可以,这个字段会被设置为Y,否则,会被设置为N。如果被设置为N,这个游标将被废弃,不再可用。

在下面的例子中,游标是可共享的并且是绑定变量敏感的,但是没有使用扩展的游标共享:

SQL代码, 略.

当游标对这个绑定变量赋不同的值执行多次以后,有趣的事情发生了。在使用值10和990执行了几次以后,视图v$sql提供的信息发生了变化。注意,0号游标不再可共享,并且产生了两个新的使用了扩展的游标共享的子游标。

查看与这个游标关联的执行计划,你可能会发现,其中一个新的子游标会使用基于全表扫描的执行计划,而同时另一个会使用基于索引扫描的执行计划:

SQL代码, 略.

有以下几个新的动态性能视图可用来进一步分析生成这两个游标的原因:v$sql_cs_statistics、 v$sql_cs_selectivity和v$sql_cs_histogram。第一个视图说明是否使用了窥测(peeking)以及对应于每个游标的相关执行统计信息。根据下面的输出,基本可以确认,对于同一个执行语句,游标1处理的记录数高于游标2处理的记录数。因此,查询优化器在一种情况下选择了全表扫描,而在另一种情况下却选择了索引扫描。

SQL代码, 略.

视图v$sql_cs_selectivity显示与每个游标的每个选择条件相关的选择性范围。事实上,数据库引擎不会为每一个绑定变量值创建一个新的游标。而是将具有同样选择性的并有可能导致生成同一个执行计划的绑定变量值组合在一起(以生成一个新的游标)。

SQL代码, 略.

总的来讲,为了提高执查询优化器生成高效的执行计划的可能性,最好不要使用绑定变量。绑定变量有时候可能有用。遗憾的是,生成的执行计划是否高效只能看运气如何。唯一的例外是,Oracle数据库11g中的新的扩展的游标共享会自动识别这个问题。

2.5.3 最佳实践

使用任何特性都需要权衡利弊得失。有些情况下,这是比较容易决定的。例如,在不涉及到Where从句(如普通的插入语句)的时候,就没理由不使用绑定变量。另一方面,在柱状图信息对查询优化器有很大影响的情况下,最好不要使用绑定变量。否则,可能会在进行绑定变量窥视的时候遇到较大负面风险。不过,还有以下两个关键案例可供参考:

  • SQL语句处理少量数据:每逢被处理的数据量很少的时候,解析时间有可能会接近甚至高于执行时间。在这种情况下,使用绑定变量就经常是一种较优选择。特别是在SQL语句将会频繁执行的情况下。数据资料系统(data entry system,常常也称之为OLTP系统)是典型的使用这种SQL语句的系统。
  • SQL语句处理大量数据:在大量数据被处理的情况下,解析时间常常比执行时间要少好几个数量级。在这种情况下,使用绑定变量对于总的响应时间(response time)几乎没有影响,但是它也会提高查询优化器生成低效的执行计划的风险。因此不要使用绑定变量。批量任务处理(batch job)、报表生成或者运用OLAP工具的数据仓库(data warehouse)环境是使用这种SQL的典型场景。

--EOF--

关于归档

本页包含 Database 类别下的所有文章.

上一类别为 Arch.

Geek 为下一类别.

回到 首页 查看最近发表的文章或者查看所有 归档文章.