有个误区:Oracle的表分区会增加查询性能,因为只需要在部分数据里查了;会增加降低插入性能,因为多了一步指定分区的操作。实际情况并非如此,至少在OLTP系统中,分区不一定会增加查询性能,但很可能会增加插入性能。
引用Tom大神的《Oracle编程艺术》的一段话,很好地解释了分区对OLTP系统的性能影响:
在OLTP系统中,不应该把分区当作一种大幅改善查询性能的方法。实际上,在一个传统的OLTP系统中,你必须很小心地应用分区,提防着不要对运行时性能产生负面作用。在传统的OLTP系统中,大多数查询很可能几乎立即返回,而且大多数数据库获取可能都通过一个很小的索引区间扫描来完成。因此,以上所列分区性能方面可能 的主要优点在OLTP系统中表现不出来。分区消除只在大对象全面扫描时才有用,因为通过分区消除,你可以避免对对象的很大部分做全面扫描。不过,在一个OLTP环 境中,本来就不是对大对象全面扫描(如果真是如此,则说明肯定存在严重的设计缺陷)。即使对索引进行了分区,就算是真的能在速度上有所提高,通过扫描较小 索引所得到的性能提升也是微乎其微的。如果某些查询使用了一个索引,而且它们根本无法消除任何分区,你可能会发现,完成分区之后查询实际上运行得反而更慢 了,因为你现在要扫描5、10或20个更小的索引,而不是一个较大的索引。稍后讨论各种可用的分区索引时还会更详细地讨论这个内容。
尽管如此,有分区的OLTP系统确实也有可能得到效率提示。例如,可以用分区来减少竞争,从而提高并发度。可以利用分区将一个表的修改分布到多个物理分区上。并不是只有一个表段和一个索引段,而是可以有10个表分区和20个索引分区。这就像有20个表而不是1个表,相应地,修改期间就能减少对这个共享资源的竞争。
事实上在一个OLTP系统中,查询已经有以下特点:即索引访问相当快,因此,分区不会让索引访问的速度有太大的提高(甚至根本没有任何提高)。这并不是说要绝对避免在OLTP系统中使用分区;而只是说不要指望通过分区来提供大幅的性能提升。尽管有效情况下分区能够改善查询的性能,但是这些情况在大多数OLTP应用中并不成立。不过在OLTP系统中,你还是可以得到另外两个可能的好处:减轻管理负担以及有更高的可用性
上面这段话在实际项目中得到了验证。项目中使用了Oracle RAC环境,在原先的AWR报表的Top Timed Event中,gc buffer busy高达70%,而DB CPU只有5%,buffer nowait只有93%,然后很快锁定到TOP等待对象均为索引对象。当时另一个有趣的现象,单机的响应时间只有RAC的40%。
解决上面问题的方法有:
- 去除不必要的索引
- 全局索引分区,并把分区分散到多个表空间中,每个表空间又有多个数据文件
- 自增长序列索引改为反向索引
这么做以后,效果显著,Top Timed Event中,gc buffer busy已经看不到了,其他集群等待时间的总和也不超过总时间的10%,DB CPU已经超过了50%,提交SQL的执行时间提高了10倍,buffer nowait也提高到了99.99%。再通过autotrace观察查询性能,发现对于查询单值的情况,响应时间几乎没有变化,而且也不必在查询时指定分区。