
1.1 什么是智能扫描
在介绍智能扫描特性之前,先简单了解一下Exadata中的数据卸载功能。数据卸载功能包括的特性非常多,比如智能扫描、智能文件创建、RMAN智能数据文件还原、智能增量备份等。智能扫描,也称为Smart Scan,是Exadata中数据卸载功能的一个子集。它同时又包含了多个子特性,比如行过滤、列映射、存储索引、布隆过滤(Bloom Filters)等。整个Exadata的数据卸载功能可以用图1.1进行简要概括。

图1.1 Exadata数据卸载功能
在讲解Exadata智能扫描特性之前,先来对“传统架构”的SQL处理和“Exadata智能扫描架构”的SQL处理做一对比。“传统架构”的SQL处理流程如图1.2所示。

图1.2 “传统架构”的SQL处理流程
“传统架构”整个SQL语句的处理流程简要描述如下。
(1)客户端向数据库服务器发起具体的SQL语句请求,查询在一次通话过程中花费超过了200元的优质顾客。(当然,这样的顾客只是极少数。)
(2)对传统架构而言,数据库服务器必须标识出包含请求的数据的所有数据区存放位置。
(3)数据库服务器向传统存储子系统发出IO扫描请求。
(4)传统存储子系统开始向数据库服务器返回所有的IO请求。
(5)数据库服务器进行数据处理,并且会丢弃不满足需求的数据。
(6)将满足条件的数据行返回给客户端。
从“传统架构”的SQL处理流程中可以看出,存储子系统传输了大量的数据块给数据库服务器,但传输的这部分数据中,绝大部分是结果集不需要的数据,数据库服务器在后期的数据处理过程中还是会丢弃这部分不需要的数据。
这种模式无形中就造成了极大的IO资源浪费。那么是否可以只传输需要的数据给数据库服务器呢?基于这个理念,所以有了现在的Exadata。
“Exadata智能扫描架构”的SQL处理流程如图1.3所示。

图1.3 “Exadata智能扫描架构”的SQL处理流程
“Exadata智能扫描架构”整个SQL语句的处理流程简要描述如下。
(1)客户端同样地向数据库服务器发起具体的SQL语句请求,查询在一次通话过程中花费超过了200元的优质顾客。(当然,这样的顾客只是极少数。)
(2)对Exadata智能扫描架构而言,数据库服务器会标识出可能包含请求的数据的所有数据区存放位置,同时会将所有数据区存放位置和元数据信息通过IDB协议传送给存储节点(这里所谓的元数据信息指的是表名、列名、过滤条件等一系列信息),因为真正的数据过滤处理工作是在存储节点完成的。
(3)存储服务器进行智能扫描工作,扫描第二步中数据库服务器定位的数据区存放位置中的所有数据块,同时根据第二步中的元数据信息进行数据处理和过滤工作,最终得到相应结果集的数据行记录和相应的列。
(4)存储服务器将最终得到的相应结果集的数据行记录和相应的列传输给数据库服务器。如果存储服务器使用了智能扫描的方式扫描数据,则向数据库服务器返回的是结果集,也即数据行和列信息,而不是数据块。
(5)数据库服务器会整合所有存储节点返回的数据行记录和相应的列,形成最终的结果集。
(6)将最终的结果集返回给客户端。
从“Exadata智能扫描架构”的SQL处理流程中可以看出,所有的数据过滤工作都在存储服务器上完成,存储服务器只将相应的结果集数据传输给数据库服务器,也即无用的数据不会传输至数据库。这种方式极大地减轻了IO传输的压力。
注意:①传统存储子系统向数据库服务器返回的是数据块,而Exadata的智能扫描向数据库服务器返回的是结果集;②Exadata上并不是所有的SQL语句都会触发智能扫描,当某条SQL语句没有触发智能扫描时,则该SQL语句的整个数据处理流程会变成“传统架构”的SQL处理流程,此时向数据库服务器返回的是数据块。
1.1.1 行过滤
行过滤是智能扫描的一个重要子特性,也称为“谓词过滤”。顾名思义,只要发起的SQL语句中带有where条件,则where条件部分就是谓词。在进行智能扫描时,只会把满足where条件的部分行记录传输给数据库服务器进行后期的数据处理,如图1.4所示。

图1.4 行过滤子特性
下面通过示例来体会智能扫描的行过滤子特性的优越表现,见代码清单1.1。首先通过将数据库参数cell_offload_processing设置成false的方式来关闭智能扫描特性,同时观察SQL语句的执行时间。
代码清单1.1 验证智能扫描的行过滤子特性(1)

从以上的代码输出可以看出,在关闭智能扫描特性的前提下,该SQL语句运行了15分钟27秒。
下面开启智能扫描特性,同时关闭智能扫描特性中的存储索引子特性,再来观察相同SQL语句的执行时间是否发生变化。
代码清单1.1 验证智能扫描的行过滤子特性(2)

在以上的代码中,清空了数据库的BufferCache,防止数据缓存干扰测试结果;同时将数据库隐含参数_kcfis_storageidx_disabled设置为true,表示禁用智能扫描的存储索引子特性。可以看到,此时只运行了20s。
代码清单1.1 验证智能扫描的行过滤子特性(3)

通过以上代码,观察相同的SQL语句在智能扫描特性关闭和开启时的表现。以上代码输出的OFFLOAD列表示该SQL语句是否进行了智能扫描。可以看出,SQL_ID为299fdyckwygkh的这条SQL语句在第一次关闭智能扫描特性的情况下,运行了927s,没有节省任何IO;而在第二次开启智能扫描并同时关闭存储索引子特性的情况下(关闭存储索引和清空数据库BufferCache的作用是尽可能地减少其他特性对测试结果的影响,在此重点关注智能扫描中的“行过滤”特性对SQL语句性能的提升),相同的SQL语句只运行了20s。在智能扫描时,存储节点过滤掉了99.95%的IO,这些无用的IO没有返回给计算节点,所以节省了大量的时间。
1.1.2 列映射
列映射同样也是智能扫描的一个重要子特性,在进行智能扫描时,只会把SQL语句中的查询列和关联列传输给数据库服务器进行后期的数据处理。所谓查询列,是指SQL语句中select关键字和from关键字之间的这一部分具体的列;而关联列,是指多表关联查询时,关联条件中所涉及的列。
列映射的处理过程如图1.5所示。例如,某张表中有A、B、C、D、E5个字段,但SQL语句只要求B、D2个字段的信息,此时如果存储服务器进行智能扫描,则只会把B和D2列的信息传输给数据库服务器。

图1.5 列映射子特性
下面通过示例来体会智能扫描的列映射子特性的优越表现,见代码清单1.2。
代码清单1.2 验证智能扫描的列映射子特性(1)

在触发智能扫描的前提下,查询test.test表的id和salary 2列的平均值,花费的时间为20s。
再次查询相同的表,但只查询id这一列的平均值,观察执行时间。
代码清单1.2 验证智能扫描的列映射子特性(2)

在触发智能扫描的前提下,查询test.test表的id列的平均值花费的时间为12s。
下面观察智能扫描的列映射子特性的表现。
代码清单1.2 验证智能扫描的列映射子特性(3)

从以上输出可以看出,两条SQL语句的智能扫描特性已经全部生效,“查询id和salary两列的平均值”这条SQL语句用时20s,“查询id这一列的平均值”这条SQL语句用时12s。这两条SQL语句都没有触发行过滤子特性和存储索引子特性。之所以“查询id这一列的平均值”这条SQL语句用时比“查询id和salary两列的平均值”这条SQL语句花费的时间少,是因为前者只会返回id这一列的数据到计算节点,而后者需要返回id和salary两列的数据到计算节点,也即SQL语句中指定的列越少,需要返回给计算节点的数据量就越少。
强调一点,SQL语句在进行智能扫描时,where条件中的非关联列不会传输到数据库服务器。下面通过示例体会这一点细微的区别,见代码清单1.3。
代码清单1.3 智能扫描的列映射不涉及谓词部分

以上示例的代码输出中,A表的object_id字段与B表的object_id字段进行关联,同时A表的owner字段作为其中的一个过滤条件,最终对A表的data_object_id字段求和。从代码清单1.3可以看出,dbms_xplan.display_cursor()函数的输出中Column Projection Information部分,也即智能扫描的列映射相关信息,仅仅提及了A表的object_id字段、data_object_id字段和B表的object_id字段,而作为过滤条件的owner字段并不在列映射的范围之内,这也间接地说明了where条件中的非关联列不会传输到数据库服务器。
1.1.3 布隆过滤
布隆过滤(Bloom Filter)是1970年由Burton Howard Bloom提出的,可以用来检索一个元素是否在一个数据集合中。布隆过滤并不是Exadata特有的特性,在Oracle 10gR2版本中布隆过滤第一次被使用,此时主要用于优化并行操作,减少并行子进程之间通信时的数据传输;到了11gR1版本时,布隆过滤特性开始支持多表关联时的裁剪。
在Exadata环境下,布隆过滤器被作为一个附加的谓词传递到存储服务器,存储服务器内部会处理这个布隆过滤器,只将满足条件的数据传输到计算节点进行数据关联操作,间接地提升SQL语句的查询性能。
下面通过示例来体会布隆过滤特性带来的性能提升,见代码清单1.4。
代码清单1.4 开启布隆过滤特性

在存储索引特性关闭的情况下,A和B这两张表进行Hash关联,布隆过滤特性默认已经开启。从以上的SQL语句执行计划也可以看出布隆过滤特性已经生效,因为在执行计划的name列中出现了:BF0000。
接着关闭布隆过滤特性,看看完全相同的SQL语句的执行效率,见代码清单1.5。
代码清单1.5 关闭布隆过滤特性

可以看出,关闭布隆过滤特性后,相同的SQL语句执行效率比之前慢了一倍。
在MOS文档FAQ related to some of the Exadata basic administration(Doc ID 1301327.1)中提及将数据库的隐含参数_bloom_pruning_enabled设置成false,可以关闭布隆过滤特性,下面通过示例进行验证,见代码清单1.6。
代码清单1.6 测试隐含参数_bloom_pruning_enabled

从以上示例可以看出,数据库的隐含参数_bloom_pruning_enabled已被设置为false,但是布隆过滤特性并没有被关闭。
查看数据库隐含参数_bloom_pruning_enabled的具体含义,见代码清单1.7。
代码清单1.7 查看隐含参数_bloom_pruning_enabled的具体含义

从隐含参数_bloom_pruning_enabled的具体含义可以看出,_bloom_pruning_enabled仅仅只是布隆过滤的一个子特性而已。如果要完全关闭布隆过滤特性,应该由隐含参数_bloom_filter_enabled进行控制。
注意:布隆过滤只有在进行hash连接的情况下才会工作。
1.1.4 函数过滤
V$SQLFN_METADATA视图中的OFFLOADABLE列表明了哪些内置函数或者操作符是允许智能扫描的,YES表示允许智能扫描,NO表示不允许智能扫描,见代码清单1.8。
代码清单1.8 查询哪些内置函数或操作符允许智能扫描

绝大部分的SQL函数或SQL操作符都是允许进行智能扫描的,以上示例只是罗列了很小的一部分内置函数和操作符而已。在编写SQL语句时,要尽量避免使用那些会影响智能扫描操作的内置函数和操作符。