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 分类 标签: on .
转载须以超链接形式标明文章原始出处和作者信息及版权声明.

TOP 第一章 之 如何解决性能问题

贴出Troubleshooting Oracle Performance 一书第一章《性能问题》的翻译稿的部分节录(初稿)。排版有点差。请多提意见。翻译的过程得到了很多朋友的大力协助,最后我会单独一一致谢!

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


如何解决性能问题?

简单而言,一个应用的目标是为使用它的业务提供便利。所以,优化一个应用性能的理由就是要最大化这种便利。这并不意味着性能的最大化,而是找到成本与性能之间的最佳平衡点。实际上,优化任务包括的努力总要从你期望获得的好处得到补偿。这意味着从商业的角度看,性能优化不总是有意义的。

业务视角 vs. 系统视角

优化一个应用的性能是为了给一个业务提供好处。所以当你着手接近(approaching)性能问题的时候,必须先理解业务问题和需求。然后才跳入应用的细节。图1-2演示了一个具有业务视角的人(一个用户)和一个具有系统视角的人(一个工程师)之间的典型不同。

TOP_CH01_01.png
图 1-2. 不同的观察者有不同的角度

认识到两种视角之间的因果关系是重要的,虽然结果必须从业务视角来识别,其原因必须从系统视角来确定。所以,如果你不想去诊断不存在或不相干的问题(强迫调优失调症),理解从业务视角看问题就变得更重要 — 即使这需要更多精细的工作。

把问题分类

对付性能问题的第一步是要从业务视角确定它们并为每个问题设定一个优先级和目标。如图1-3所示。

从业务视角来确定问题 > 设定每个问题的优先级 > 设定每个问题的优化目标

业务问题不能通过观察系统统计发现,而必须从业务视角来确定。如果代之以监控服务等级协议,很明显,可以从没有满足期望的操作来确定性能问题。否则,除了询问用户或者负责的人之外没有其他可能性。这种讨论将涉及一系列操作。例如:注册一个新用户,运行一个报告或加载一批可能很慢的数据。

你知道哪些是有问题的操作,就该给他们排个优先级了。考虑类似这样的问题:如果我们只能处理5个问题,应该如何做呢?当然,最好是全部解决它们。但有时候时间或预算是有限的。此外,缺乏必要措施的情况下,不可能解决不同问题的相互冲突。要强调的是在设定优先级时,当前的性能可能是不相干的。例如,如果你处理一整套报告,不一定最慢的那个具有最高的优先级。可能最快的那个也是执行最频繁的那个,因此有可能具有最高优先级并需要首先优化。再说一次,是业务需求在驱动你。

对每项操作,你应当为优化设定一个可量度的目标。诸如”当创建用户按钮按下以后,处理时间最多2秒”。如果性能需求甚至服务等级协议可以得到,可能目标已经知道了。否则,再强调一次,必须考虑业务需求去确定目标。注意,没有目标就不知道何时停止研究一个更好的解决方案。换言之,优化可以是无止境的。记住,努力永远要和获利取得平衡。

解决问题

诊断整个系统比诊断一个单独的组件要复杂得多。因此,任何可能的时候,你应当一次只解决一个问题,简单地从问题列表按照优先级从高到低的顺序解决。

对每个问题,如图1-4所示,必须回答3个问题:

  • 时间花在哪里了?首先,你必须确定时间花在哪里了。例如,如果一个特定操作用时10秒,你必须找到这10秒里绝大部分花在哪个模块或组件。

  • 时间是如何耗费的?一旦你知道时间花在哪里了,你必须找到时间是如何耗费的。例如,你发现应用用了4.2秒在CPU上,0.4秒做I/O操作,5.1秒等待另一个组件发出队列出队消息。
  • 如何减少时间耗费?最后,才是找出怎样使操作更快的时候。要做到这个,重要的是聚焦到处理中最大时间消费的部分。例如,如果I/O操作占整个处理时间的4%,那么即使它很慢也没必要对他进行调整。
时间花在哪里了? > 时间是如何耗费的? > 如何减少时间耗费? 

要注意由于副作用的益处,有时候修复一个特定问题的同时也会修复另一个问题。当然,相反的情况也会发生。采取的措施可能引入新的问题。所以,很有必要认真考虑修复过程中可能引起的所有副作用。显然,所有改变在应用到生产环境前都要经过仔细测试。

EOF

此文作者:, 位于 Database 分类 标签: on .
转载须以超链接形式标明文章原始出处和作者信息及版权声明.

日落西山 – Oracle 收购 Sun

真是一种嘲讽,就在刚才,收到一封广告信,标题是 "Sun为企业发展提供更多动力"

对于 IT 产业来说,这是最好的时代,这是最坏的时代。Sun 要做 Web 2.0 中的这个 Dot 没做成,74 亿美金把自己卖掉了。

zot_sun_s_oracle_b.gif

尽管我不是 Sun 的粉丝,还是感觉不太痛快。这次收购意味着又有若干产品有可能被打入冷宫。而大家比较关心的 MySQL 可谓命运不济,被 Sun 折腾一年多,在开源社区里面一点好没讨到,这回在 Oracle 新的产品线里面如何定位呢? will be an addition to Oracle’s existing suite of database products… 当然,InnoDB 这回和 MySQL 算是破镜重圆了。是否有其它变数,比如被原 MySQL 团队赎身出来? 难!

对于 Oracle 来说,这次自己终于有了硬件(SPARC)和操作系统(Solaris)这两块王牌,其实 Oracle 和 Sun 算是多年的合作伙伴了(超过 25 年),相信整合起来可能问题不大。这次收购比较失败的可能就是 IBM 了,Oracle 这次给了竞争对手 IBM 以更大的压力。难道蓝色巨人出不起这个价格麽? 还是觉得足够鸡肋? Sun 手里的 Java 技术对于 IBM 的小型机是个很好的补充,想不通。再过几年,这可能就是 IBM 犯过的最大错误。

不痛快的除了 IBM ,恐怕还有 RedHat。不过别着急,没准儿哪天 Oracle 也把 RedHat 也一并收了,我相信 RedHat 手里的 JBoss 至少让 Oracle 眼馋不已。有 JBoss 在,其他中间件就不可能赚到更多。

一切皆有可能。其他事情不好确定,但有件事情还是能基本肯定,拉里·埃里森大叔这回又有机会体验一下世界首富的滋味了…

EOF
延伸阅读:

小规模低性能低流量网站设计原则

到处都是什么大规模啊,高流量啊,高性能之类的网站架构设计,这类文章一是满足人们好奇心,但看过之后也就看过了,实际收益可能并不大;另外一个副作用是容易让人心潮澎湃,没学走先学跑,在很多条件仍不具备的情况下,过度设计、过度扩展(高德纳大爷也说过,”过早优化是万恶之源”),所以,这里反弹琵琶,讨论一下小规模低性能低流量的网站该如何搞法。

如果站点起步阶段可能就是一台机器(或是一台虚拟机,比如 JobsDigg.com ),这个时候,去关注什么数据拆分啊,负载均衡啊,都是没影子的事情。很多大站点的经验绝不能照搬,辩证的参考才是硬道理。

拥抱熟知的技术

动手构建站点的时候,不要到处去问别人该用什么,什么熟悉用什么,如果用自己不擅长的技术手段来写网站,等你写完,黄花菜可能都凉了。所以,有现成的软件组件可用,就不要自己重新发明轮子。人家说 Python 牛,但自己只懂 PHP ,那就 PHP 好了,如果熟悉 .net ?,那也不错。用烂技术不是丢人的事情,把好技术用烂才丢人。

架构层次清晰化

起步的阶段应该清楚的确定下来架构的层次。如果都搅和在一起,业务一旦扩增开来,如果原有的一堆东西拆不开就是非常痛苦的事情。

Web Server <--> (AppServer)<-->Cache(eg. Memcached)<-->DB

层次清晰化的一个体现是(以 LAMP 架构为例):即使只有一台机器,也应该起个 Memcached 的实例,效果的确非常好(除非内存小)–一般人儿我不告诉他…不要把什么都压到 DB 上,DB 一旦 I/O 压力走到磁盘上,问题要暴露出来是很快的。没错,DB 本身也会利用自己的 Cache,但 DB 的Cache 和 Memcached 设计出发点毕竟不一样。

数据冗余? 有必要

很多人并不是数据库设计专家,如果应用要自己设计表结构什么的,基本都是临时抱佛脚,但三个范式很多人倒是记得牢,这是大多数小型 Web 站点遇到的一个头疼事儿,一个小小的应用搞了几十个表… 忘掉范式这个玩意儿! 记住,尽可能的冗余数据,你在数据层陷入的时间越多,你在产品上投入的就会越少。用户更关心的是产品的设计。

前端优化很重要

因为流量低,访客可能也不多,这时候值得注意的是页面不要太大,多数流量低的站点吃亏就在于一个页面动辄几兆(我前两天看到一个Startup的首页有4M之大,可谓惊人),用户看个页面半分钟都打不开,你说咋发展? 先把基本的条件满足,再去研究前端优化

功能增加要谨慎

不是有个 80/20 原则么? 把最重要的精力放在最能给你带来商业价值的地方。有些花里胡哨的功能带来很大的开销,反而收效甚微。记住,小站点,最有价值的是业务模式,而不是你的技术有多牛。技术是为业务服务的,不要炫技。

有些网站不停的添加功能,恰恰是把这些新功能变成了压死自己的稻草。

从开始考虑性能

这一点是可选的,但也重要。设计应用的时候在开始就应考虑 Profile 这件事情。一套应用能否在后期进行有效优化和扩展,很大的程度限制在是否有比较合适的 Profile 机制上。需要补充的是,对性能的考虑必然要把有关的历史数据考虑进来。另请参见网站运维之道的容量规划以及其它小帖子。

好架构不是设计出来的

这是最后要补充的一点。好的架构和最初的设计有关系,但最重要的是发展中的演化:

发展-->发现问题-->反馈-->解决问题(执行力)--> 改进->进化到下一阶段--新问题出现(循环)

有些站点到了某个阶段停足不前,可能卡在执行力这个地方,来自用户的反馈意见上来了之后,没有驱动力去做改进。最后也是死猪不怕开水烫了。最怕听到的就是”业务不允许”的托词,试想如果不改进业务都没了,那业务还允许么? 其实就是一层心理障碍。

这篇文章有浓重的山寨风格,所以,你不要太认真。如果在用短、平、快的方式构建某些山寨网站的话,可参考其中对你有益的点,不赞同的地方可以直接忽视掉,就没必要费力留言进行争论了。

EOF

  • 好的业务模式(产品) + 很好的技术 = 大赚钱
  • 好的业务模式(产品) + 能用的技术 = 也赚钱
  • 差的业务模式(产品) + 好的技术 = 赚吆喝(现在的SNS就差不多这样了)
  • 差的业务模式(产品) + 差的技术 = 自己浪费资源
此文作者:, 位于 Arch 分类 标签: on .
转载须以超链接形式标明文章原始出处和作者信息及版权声明.