Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154674
  • 博文数量: 39
  • 博客积分: 825
  • 博客等级: 准尉
  • 技术积分: 955
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-25 14:05
文章分类

全部博文(39)

文章存档

2014年(4)

2013年(13)

2012年(22)

我的朋友

分类: Oracle

2012-11-04 23:06:55

【建立初始环境】

ALTER SESSION SET db_file_multiblock_read_count=8;
ALTER SESSION SET optimizer_mode=ALL_ROWS;
ALTER SESSION SET statistics_level=ALL;
ALTER SESSION SET "_optimizer_cost_model"='IO';  --禁用cpu_costing

--建立实验表空间
SELECT dbms_metadata.get_ddl('TABLESPACE', 'UNIFORM_TBS') from dual;
CREATE TABLESPACE UNIFORM_SIZE_TBS DATAFILE
'D:\APP\ADMINISTRATOR\ORADATA\ZHANGYU\UNIFORM_SIZE_TBS01.DBF' SIZE 100M
AUTOEXTEND ON NEXT 8192 MAXSIZE 32767M
BLOCKSIZE 8192  --8k大小的块
EXTENT MANAGEMENT LOCAL --本地管理表空间
UNIFORM SIZE 1048576   --固定extent大小
SEGMENT SPACE MANAGEMENT MANUAL;  --非assm管理

【创建实验表】

CREATE TABLE t1 TABLESPACE UNIFORM_SIZE_TBS PCTFREE 99 PCTUSED 1
AS
SELECT LEVEL AS ID,
       TRUNC(dbms_random.normal * 100) AS val,
       RPAD('x', 100) AS padding
FROM   dual
CONNECT BY LEVEL <= 10000;

--收集统计信息
BEGIN
  dbms_stats.gather_table_stats(ownname          => USER,
                                tabname          => 't1',
                                estimate_percent => 100,
                                method_opt       => 'for all columns size 1',  --不生成直方图
                                cascade          => TRUE);
END;
/

SELECT t.HISTOGRAM
FROM   user_tab_col_statistics t
WHERE  t.table_name = 'T1';
/*
NONE
NONE
NONE
*/

SELECT uts.NUM_ROWS,
       uts.BLOCKS,
       uts.AVG_ROW_LEN
FROM   user_tab_statistics uts
WHERE  uts.TABLE_NAME = 'T1';
--10000 10000 109

SELECT column_name,
       num_distinct,
       utl_raw.cast_to_number(HEXTORAW(low_value)) numl,
       utl_raw.cast_to_varchar2(HEXTORAW(low_value)) charl,
       utl_raw.cast_to_number(HEXTORAW(high_value)) numh,
       utl_raw.cast_to_varchar2(HEXTORAW(high_value)) charh,
       density,
       num_nulls,
       avg_col_len
FROM   user_tab_col_statistics utcs
WHERE  utcs.table_name = 'T1';

COLUMN_NAME     NUM_DISTINCT       NUML CHARL                      NUMH CHARH                   DENSITY  NUM_NULLS AVG_COL_LEN
--------------- ------------ ---------- -------------------- ---------- -------------------- ---------- ---------- -----------
ID                     10000          1 ?                         10000 ?                         .0001          0           4
VAL                      587       -367 =b"f                        416 ?                   .001703578          0           4
PADDING                    1 -6.97E-115 x                    -6.97E-115 x                             1          0         101

【初试 - 简单表扫描】

SELECT MAX(val) FROM t1;

-----------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost  |
-----------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |     4 |  1519 |
|   1 |  SORT AGGREGATE    |      |     1 |     4 |       |
|   2 |   TABLE ACCESS FULL| T1   | 10000 | 40000 |  1519 |
-----------------------------------------------------------
Note
-----
   - cpu costing is off (consider enabling it)
  
  我们看到扫描10000个块的cost成本(纯io)是1519,对应处理的数据量是
是40000bytes (num_rows * avg_col_len)。

【修改db_file_multiblock_read_count】

ALTER session SET db_file_multiblock_read_count=16;
|   2 |   TABLE ACCESS FULL| T1   | 10000 | 40000 |   963 |
-----------------------------------------------------------

ALTER session SET db_file_multiblock_read_count=32;
|   2 |   TABLE ACCESS FULL| T1   | 10000 | 40000 |   611 |
-----------------------------------------------------------

ALTER session SET db_file_multiblock_read_count=64;
|   2 |   TABLE ACCESS FULL| T1   | 10000 | 40000 |   388 |
-----------------------------------------------------------

ALTER session SET db_file_multiblock_read_count=128;
|   2 |   TABLE ACCESS FULL| T1   | 10000 | 40000 |   246 |
-----------------------------------------------------------

ALTER session SET db_file_multiblock_read_count=256;
|   2 |   TABLE ACCESS FULL| T1   | 10000 | 40000 |   157 |
-----------------------------------------------------------

【io_cost公式】

  通过查看sys.Aux_Stats$发现,目前只存在noworkload系统统计信息,所以
对应io_cost计算公式为:
COST = io COST = blocks / ( POWER(db_file_multiblock_read_count,0.6581)*1.6765 )

SELECT round(10000 / (POWER(8, 0.6581) * 1.6765) + 1) COST FROM dual;
SELECT round(10000 / (POWER(16, 0.6581) * 1.6765) + 1) COST FROM dual;
SELECT round(10000 / (POWER(32, 0.6581) * 1.6765) + 1) COST FROM dual;
SELECT round(10000 / (POWER(64, 0.6581) * 1.6765) + 1) COST FROM dual;
SELECT round(10000 / (POWER(128, 0.6581) * 1.6765) + 1) COST FROM dual;
SELECT round(10000 / (POWER(256, 0.6581) * 1.6765) + 1) COST FROM dual;

  我们发现上面各sql计算出来的cost与实际中差距并不大,而+1操作是因为下面这个
隐含参数设置为true的原因:

SELECT n.ksppinm  AS NAME,
       v.ksppstvl AS val
FROM   x$ksppi  n,
       x$ksppcv v
WHERE  n.indx = v.indx
AND    n.ksppinm = '_table_scan_cost_plus_one';
--_table_scan_cost_plus_one TRUE

【总结】

  非workload下的io成本计算公式并不是官方给出的,而且要
记住这个公式的一些因子的值随着版本的不同而不同,但是他
们都有一个统一的目的:在cbo评估成本时,告诉它一次性读取
的块数总是比期望值要小一些,而我们知道一些打断多块读的
情况有:

  段头块读
  中间遇到缓冲块
  达到一个区的边界块则重启多块读
...
阅读(1569) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~