[English]
作者:
fuyuncat
来源:
www.HelloDBA.com
为了降低服务端的负荷,oracle引入一些特性,将部分工作移到客户端去处理。Row shipping就是其中之一。
我们知道,Oracle对于SQL的处理由几个步骤组成:解析(Parse)->优化(Optimize)->生产数据源(Row Source Generate)->返回结果(Result Product)。在传统模式下,数据源生成组件(Row Source Generator)要做一步工作就是从记录中找出SELECT子句的中出现的字段,返回给客户端,这一过程称为投射(Projection)。我们可以通过DBMS_XPLAN(10g)查看查询计划中的投射字段信息:
SQL代码
- HELLODBA.COM>create table WIDE_TBL as select * from sys.gv_$session;
- Table created.
- HELLODBA.COM>explain plan for select sid,audsid,serial# from WIDE_TBL;
- Explained.
- HELLODBA.COM>select * from table(dbms_xplan.display(null,null,'ADVANCED'));
- PLAN_TABLE_OUTPUT
- ---------------------------------------------------------------------------------------------------------
- Plan hash value: 1188828058
- ------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 25 | 975 | 3 (0)| 00:00:01 |
- | 1 | TABLE ACCESS FULL| WIDE_TBL | 25 | 975 | 3 (0)| 00:00:01 |
- ------------------------------------------------------------------------------
- ...
- Column Projection Information (identified by operation id):
- -----------------------------------------------------------
- 1 - "SID"[NUMBER,22], "SERIAL#"[NUMBER,22], "AUDSID"[NUMBER,22]
- Note
- -----
- - dynamic sampling used for this statement
- 36 rows selected.
对字段的投射是需要消耗CPU的,尤其是一些“宽表(Wide Table)”,含有大量字段,并且需要选择其中大部分字段时,CPU的消耗就更大。Row shipping就是为降低数据源生成组件在服务器消耗的CPU而在10g中引入的一个新机制。其基本思想就是将返回的记录完整的传输(ship)给客户端,并且将投射的工作由服务器端转交给客户端完成。参数_enable_row_shipping控制是否启用该特性,_row_shipping_threshold则控制当投射多少字段时激活该特性(即投射字段数小于该值时不会启用row shipping)。此外,参数_row_shipping_explain控制是否在查询计划中包含该特性是否已被激活的信息,但其并不会影响该特性是否被启用。我们看下该特性给SQL执行带来的变化:
SQL代码
- HELLODBA.COM>analyze table WIDE_TBL compute statistics for table for all columns;
- Table analyzed.
- HELLODBA.COM>select num_rows*avg_row_len from dba_tables where table_name='WIDE_TBL';
- NUM_ROWS*AVG_ROW_LEN
- --------------------
- 8492
- HELLODBA.COM>set autot trace stat
- HELLODBA.COM>alter session set "_enable_row_shipping" = FALSE;
- Session altered.
- HELLODBA.COM>alter session set events '10079 trace name context forever, level 2';
- Session altered.
- HELLODBA.COM>select sid,audsid from WIDE_TBL;
- 22 rows selected.
- Statistics
- ----------------------------------------------------------
- 1 recursive calls
- 0 db block gets
- 6 consistent gets
- 0 physical reads
- 0 redo size
- 846 bytes sent via SQL*Net to client
- 396 bytes received via SQL*Net from client
- 3 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 22 rows processed
- HELLODBA.COM>alter session set events '10079 trace name context off';
- Session altered.
- HELLODBA.COM>conn demo/demo@erdb
- Connected.
- HELLODBA.COM>set autot trace
- HELLODBA.COM>alter session set "_enable_row_shipping" = TRUE;
- Session altered.
- HELLODBA.COM>alter session set "_row_shipping_explain" = TRUE;
- Session altered.
- HELLODBA.COM>alter session set "_row_shipping_threshold" = 2;
- Session altered.
- HELLODBA.COM>alter session set events '10079 trace name context forever, level 2';
- Session altered.
- HELLODBA.COM>select sid,audsid from WIDE_TBL;
- 22 rows selected.
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 1188828058
- ------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 22 | 132 | 3 (0)| 00:00:01 |
- | 1 | TABLE ACCESS FULL| WIDE_TBL | 22 | 132 | 3 (0)| 00:00:01 |
- ------------------------------------------------------------------------------
- Note
- -----
- - row shipping is enabled for this statement
- Statistics
- ----------------------------------------------------------
- 358 recursive calls
- 0 db block gets
- 38 consistent gets
- 0 physical reads
- 0 redo size
- 9223 bytes sent via SQL*Net to client
- 396 bytes received via SQL*Net from client
- 3 SQL*Net roundtrips to/from client
- 6 sorts (memory)
- 0 sorts (disk)
- 22 rows processed
- HELLODBA.COM>alter session set events '10079 trace name context off';
- Session altered.
可以看到,因为Row Shipping影响的是Row Source Generator,所以Logical IO并没有变化。但是,从SQL*Net发送到客户端的字节数可以看到其产生的变化:尽管只需要返回2个字段的数据,Row Shipping将记录的全部字段(通过平均值大致估算为8492字节)都直接发送到了客户端,再加上字段本身的信息(名称、类型、长度),因而row shipping发送到客户端的数据是9223字节。
而如果对通过10079事件捕捉到的SQLNet的内容我们也可以看出Row Shipping和传统方式的这一不同之处:
SQL代码
- ...
- A798440 53038001 80015359 3016C506 FF2D2531 [...SYS.....01%-.]
- A798450 4E4908FF 49544341 44094556 43494445 [..INACTIVE.DEDIC]
- A798460 44455441 53038001 68075359 676E6175 [ATED...SYS.huang]
- A798470 32096465 3A363932 34343737 434F4F0E [ed.2296:7744.OOC]
- A798480 5C4D444C 4E415548 07444547 4E415548 [LDM\HUANGED.HUAN]
- A798490 0C444547 71736C70 7665646C 6578652E [GED.plsqldev.exe]
- A7984A0 45535504 01000152 04FFFF80 5432B92C [.USER.......,.2T]
- A7984B0 0423C506 0D146339 327A6E33 35763036 [..#.9c..3nz260v5]
- A7984C0 6E717764 FF800176 10FFFFFF 532F4C50 [dwqnv.......PL/S]
- A7984D0 44204C51 6C657665 7265706F 5B0CC506 [QL Developer...[]
- A7984E0 0C40430E 6E69614D 73657320 6E6F6973 [.C@.Main session]
- A7984F0 4A12C506 FF5B5020 480CC304 02C2031E [...J P[....H....]
- ...
此外,在传统方式下,为了减少网络流量,Oracle通过SQL*Net传输数据时,会先对数据进行压缩后再传输,而以row shipping传输的数据则基本没有进行压缩:
SQL代码
- HELLODBA.COM>create table WIDE_TBL2 as select a.* from WIDE_TBL a, WIDE_TBL b, WIDE_TBL c;
- Table created.
- HELLODBA.COM>analyze table WIDE_TBL2 compute statistics for table for all columns;
- Table analyzed.
- HELLODBA.COM>select num_rows*avg_row_len from dba_tables where table_name='WIDE_TBL2';
- NUM_ROWS*AVG_ROW_LEN
- --------------------
- 4110128
- HELLODBA.COM>conn demo/demo@erdb
- Connected.
- HELLODBA.COM>set autot trace stat
- HELLODBA.COM>alter session set "_enable_row_shipping" = TRUE;
- Session altered.
- HELLODBA.COM>select * from WIDE_TBL2;
- 10648 rows selected.
- Statistics
- ----------------------------------------------------------
- 0 recursive calls
- 0 db block gets
- 1268 consistent gets
- 0 physical reads
- 0 redo size
- 4260321 bytes sent via SQL*Net to client
- 8184 bytes received via SQL*Net from client
- 711 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 10648 rows processed
- HELLODBA.COM>alter session set "_enable_row_shipping" = FALSE;
- Session altered.
- HELLODBA.COM>select * from WIDE_TBL2;
- Statistics
- ----------------------------------------------------------
- 1 recursive calls
- 0 db block gets
- 1268 consistent gets
- 0 physical reads
- 0 redo size
- 258356 bytes sent via SQL*Net to client
- 8184 bytes received via SQL*Net from client
- 711 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 10648 rows processed
可以看到,尽管是获取到表的全部内容,Row Shipping方式传输的数据量是表数据量加元数据信息之和,而传统方式下,经过压缩后传输的字节数远远小于表数据的字节数。这样做的目的也是为了减少数据压缩在服务端带来的负荷。
从前面的分析看,Row Shipping带来的最大好处就是减少了Row Source Generator在服务端的消耗,按理我们可以从Row Source的相关统计数据看到这些变化,遗憾的是,如果一旦打开_rowsource_execution_statistics或者SQL Trace(10046)进行统计数据收集时,Row Shipping就不会被激活,这使得我们无法获取到相关性能统计数据做比较。
--- Fuyuncat Mark ---