Exadata中最有用的功能-存储索引
前所未闻的存储索引是Exadata中最有用的功能,它不是像Oracle的B树索引或者位图索引那样传统的存储在数据库中的索引,事实上,它在传统意义上甚至根本不能算是索引。我们无法通过存储索引来定位拥有给定列上特定值的一系列记录,相反的,存储索引是存储服务器上的软件,它的设计目的是为了消除磁盘I/O。因为通过存储索引可以定位的是不存在所需记录的位置而非存在的位置,所以有时候我们称其为“反向索引”。它保存每个磁盘存储单元(默认是1MB大小)中存储的字段的最小值和最大值,当使用智能扫描时,SQL谓词是会传递到存储服务器中的,因此存储软件就能在真正请求I/O之前比对谓词和存储索引元数据(最大值和最小值),任何不可能包含匹配记录的存储区间都会被跳过,在很多情况下,这将大幅度减少需要执行的I/O量。需要记住的是,由于存储软件需要谓词来跟存储索引中保存的最大与最小值进行比较,因此只有在智能扫描时此优化才生效。
并没有文档记录存储软件维护和优化存储索引的算法(虽然确实在启动cellsrv前可以在存储服务器上设置几个隐含参数),实际上,甚至没有什么方法来监控存储索引,比如说,当存储索引被读取或者被更新的时候,并没有什么等待事件来记录消耗的时间。即使没有任何命令可以用来操纵存储索引,但是因为这是一个非常强大的功能,能带来显著的性能改善,因此了解它是如何工作的还是很重要的。
Kevin说:为了加深我自己心目中存储索引的形象,我通常将这种优化手段勾勒成这样一个画面,极大提高在草垛中寻找一根银针的效率,而非在草垛中寻找某一根稻草。
结构
存储索引包含了最多8列的最小值和最大值,对于每1MB存储单位(存储区间)上都维护这样的结构,存储索引只保存在内存中而永远不会写入磁盘。
Kevin说:存储索引保存在cellsrv的堆(heap)中,所以从技术上而言,在某些极端场景下,是可能会跑到磁盘上的(交换区)……所以,也不能说是永远不会……
图4-1显示存储索引中所含数据的概念图。
如图4-1中所示,Customer表中的第一个存储区间中cust_age字段最大值为77,这表明它是有可能包含满足查询条件的记录的(cust_age > 35),而图中的其他存储区间所包含的最大值不足以满足查询条件,因此就根本不会从磁盘读取这些存储区间。
除了最小值和最大值,还有一个标识表示了在存储区间中是否存在包含空值(NULL)的记录。在索引中存在空值指示着实有些让人吃惊,因为在传统的Oracle索引中都是不会保存空值的,存储索引这种跟踪空值的能力,实际上也许是受到设计方法和实现方法的影响,有些系统是完全不用空值的,比如SAP就使用一个空格来代替NULL,SAP这样做就是为了保证记录可以通过B树索引(该类索引不保存空值)查询到。无论如何,存储索引提供了一个类似于空值上的位图索引一样的功能,这使得寻找空值效率很高(假设空值只占一小部分)。
监控存储索引
监控存储索引的功能非常有限,优化器并不知道在一个SQL语句中存储索引是不是会被使用,AWR和ASH也同样捕捉不到任何有关存储索引在SQL中是否使用到的信息,仅仅在数据库级别有一个统计值可以跟踪存储索引的使用,另外还有一个未公开的跟踪机制。
数据库统计值
只有一个数据库统计值跟存储索引有关,就是“cell physical IO bytes saved by storage index”,记录了因为使用了存储索引而被避免的I/O累计值。该统计值可以从v$sesstat和v$sysstat等相关视图中查到,虽然这个统计值比较奇怪、并不精准,不过这是唯一一个可以轻易获取的显示存储索引是否被使用到的指标。很不幸,由于统计值是累加的,就跟v$sesstat中的所有其他统计值一样,必须要在SQL语句执行前和执行后都检查该值才能确定存储索引是否被使用了。下面是一个例子:
SYS@EXDB1> set echo on
SYS@EXDB1> @si
SYS@EXDB1> col name for a70
SYS@EXDB1> col value for 99999999999999
SYS@EXDB1> select name, value
2 from v$mystat s, v$statname n
3 where n.statistic# = s.statistic#
4 and name like '%storage%';
NAME VALUE
--------------------------------------------- ---------------
cell physical IO bytes saved by storage index 0
SYS@EXDB1> select avg(pk_col) from kso.skew2 where col1 is null;
AVG(PK_COL)
-----------
32000001
SYS@EXDB1> set echo off
SYS@EXDB1> @si
NAME VALUE
--------------------------------------------- ---------------
cell physical IO bytes saved by storage index 3984949248
SYS@EXDB1> select avg(pk_col) from kso.skew2 where col1 is null;
AVG(PK_COL)
-----------
32000001
SYS@EXDB1> @si
NAME VALUE
--------------------------------------------- ---------------
cell physical IO bytes saved by storage index 7969898496
正如你所见,si.sql脚本在v$mystat视图中查询包含“storage”单词的统计值,除非当前会话中有SQL语句使用了存储索引否则该统计值将为0。在我们的例子中,使用到存储索引的查询大概消减了40亿字节 的磁盘I/O,这些都是没有存储索引时不得不进行的额外I/O。由于v$mystat视图显示的是你当前会话的累计统计值,所以如果你再次执行这个语句,该值就会比第一次执行之后增加一倍,当然断开会话(比如说退出SQL*Plus)会将v$mystat视图中包括该统计值在内的大多数统计值都清零。
本文节选自《深入理解Oracle Exadata》一书
Kerry Osborne(凯里•奥斯本)
Randy Johnson(兰迪•约翰逊)
Tanel Põder(托内耳•卜戴德)著
黄凯耀,张乐奕,张瑞译
电子工业出版社出版
图书详细信息:http://bvbroadview.blog.51cto.com/addblog.php