现在你可能已经认识到了查询重写特性是多么有用和重要。它能大大降低I/O和处理过程、返回结果更快。
还是假定以上的例子,用户执行一个下面的查询:
请注意consistent gets的值是6——一个非常低的值。这一结果是基于这个查询已经基于从3张表创建的2个视图的查询重写。不是从表查询,而是从MV查询,一次消耗了更少的如磁盘IO和CPU的资源。1 SQL> Select city, sum(actual_rate) 2 from hotels h, reservations r, trans t 3 where t.resv_id = r.resv_id 4 and h.hotel_id = r.hotel_id 5 group by city; 0 recursive calls 0 db block gets 6 consistent gets 0 physical reads 0 redo size 478 bytes sent via SQL*Net to client 496 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk)
但是如果查询重写失败了会怎么样呢?可能会以为几个原因失败:如果初始化参数query_rewrite_integrity被设置为TRUSTED并且MV的状态为STALE,查询就不会被重写。你可以通过设置会话的参数来模拟这一过程。
执行这一命令后,查询计划显示是从3张表查询数据,而不是从MV:SQL> alter session set query_rewrite_enabled = false;
请注意consistent gets的值:从6上升到了16。在真实环境中,这一结果恐怕是无法接受的。因为多出来的资源请求可能无法获得,而你就必须自己重写这一查询了。在那样的情况下,你就必须确保查询一定能被重写。0 recursive calls 0 db block gets 16 consistent gets 0 physical reads 0 redo size 478 bytes sent via SQL*Net to client 496 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 2 sorts (memory) 0 sorts (disk)
在Oracle 9i和以下版本中,可能只有一个方法实现:使查询重写失效而不是使基础表的访问失败。在10g中通过一个特殊的提示可以提供这样的机制:REWRITE_OR_ERROR。上面这个查询就可以这样写了:
这样就会产生一个ora-30393的错误信息。这个信息表示查询不能通过使用MV来重写,因此语句失败。这一错误保护可以防止查询长期运行后系统发生资源缺乏问题。但是还要注意一个潜在问题:如果一个查询成功了,而不是所有都成功了,这些MV就能被用于查询的重写。因此,如果MV_ACTUAL_SALES而不是MV_HOTL_RESV能被使用,查询将会重写,错误也不会产生。这种情况下,查询计划就如以下:1 SQL> select /*+ REWRITE_OR_ERROR */ city, sum(actual_rate) 2 from hotels h, reservations r, trans t 3 where t.resv_id = r.resv_id 4 and h.hotel_id = r.hotel_id 5 group by city; from hotels h, reservations r, trans t * ERROR at line 2: ORA-30393: a query block in the statement did not rewrite
这一查询使用了MV_ACTUAL_SALES而不是MV_HOTEL_RESV,这样,表HOTELS和RESERVATIONS就能够访问。这种情况下,特别使对后面两种表会做全表扫描的情况下,将会消耗更多的资源——在你创建MV和设计查询语句时要特别注意。Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=6 Bytes=156) 1 0 SORT (GROUP BY) (Cost=11 Card=6 Bytes=156) 2 1 HASH JOIN (Cost=10 Card=80 Bytes=2080) 3 2 MERGE JOIN (Cost=6 Card=80 Bytes=1520) 4 3 TABLE ACCESS (BY INDEX ROWID) OF 'HOTELS' (TABLE) (Cost=2 Card=8 Bytes=104) 5 4 INDEX (FULL SCAN) OF 'PK_HOTELS' (INDEX (UNIQUE)) (Cost=1 Card=8) 6 3 SORT (JOIN) (Cost=4 Card=80 Bytes=480) 7 6 TABLE ACCESS (FULL) OF 'RESERVATIONS' (TABLE) (Cost=3 Card=80 Bytes=480) 8 2 MAT_VIEW REWRITE ACCESS (FULL) OF 'MV_ACTUAL_SALES' (MAT_VIEW REWRITE) (Cost=3 Card=80 Bytes=560)
尽管你已经通过资源管理器(Resource Manager)控制资源使用,使用这一提示能防止在资源管理器被调用前查询被执行。资源管理器基于优化器的统计数据来降低资源的消耗,因此统计数据的有无将会影响这一过程。而“重写还是报错”这一特性将会不管有误统计数据都会阻值表的访问。