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

全部博文(39)

文章存档

2014年(4)

2013年(13)

2012年(22)

我的朋友

分类: Oracle

2012-11-20 15:34:27

/******************************************************************************/
--1.创建测试表
 

  1. DROP TABLE clftr_anl PURGE;
  2.   CREATE TABLE clftr_anl(ID INT,scatt INT) TABLESPACE dict_tabs;
  3.   INSERT INTO clftr_anl
  4.     SELECT LEVEL, MOD(LEVEL, 20) FROM dual CONNECT BY LEVEL <= 10000;
  5.   COMMIT;
  6.   --创建索引

  7.   CREATE INDEX ind_clftr_anl ON clftr_anl(ID);
  8.   CREATE INDEX ind_clftr_anl1 ON clftr_anl(scatt);
  9.   --收集统计信息

  10.   BEGIN
  11.     dbms_stats.gather_table_stats(ownname => USER,
  12.                                   tabname => 'clftr_anl',
  13.                                   estimate_percent => 100,
  14.                                   method_opt => 'for all columns size 1',
  15.                                   cascade => TRUE);
  16.   END;
  17.   /

  
  --查看索引统计信息
  SELECT ui.index_name,
         ui.clustering_factor,
         ui.leaf_blocks,
         ui.avg_leaf_blocks_per_key,
         ui.avg_data_blocks_per_key
  FROM   user_ind_statistics ui
  WHERE  ui.table_name = upper('clftr_anl');
  /*
  IND_CLFTR_ANL1 340 20 1 17
  IND_CLFTR_ANL   17 21 1 1
  */
 
  SELECT blocks
  FROM   user_tab_statistics ut
  WHERE  ut.table_name = upper('clftr_anl');
  --20
 
  SELECT COUNT(DISTINCT dbms_rowid.rowid_block_number(ROWID)) bcnt
  FROM   clftr_anl;
  --17

/******************************************************************************/
--2.手工计算cluster factoring
 

  1. WITH t1 AS
  2.   (
  3.     SELECT /*+index(t) no_index_ffs(t) noparallel_index(t)*/
  4.      dbms_rowid.rowid_relative_fno(ROWID) || '.' ||
  5.      dbms_rowid.rowid_block_number(ROWID) fbno
  6.     FROM clftr_anl t
  7.     WHERE ID IS NOT NULL
  8.   ),t2 AS
  9.   (
  10.     SELECT fbno, lag(fbno,1,-100) over(ORDER BY NULL) AS lg_fbno FROM t1
  11.   ),t3 AS
  12.   (
  13.   SELECT t2.*,
  14.          CASE
  15.            WHEN fbno <> lg_fbno THEN
  16.             1
  17.            ELSE
  18.             0
  19.          END AS flag
  20.   FROM t2
  21.   )
  22.   SELECT SUM(flag) AS cluster_factoring FROM t3;
  23.   --17  

/******************************************************************************/
--3.使用clustering_factor函数,它来自Christian Antognini:
 

  1. CREATE OR REPLACE FUNCTION clustering_factor
  2.   (
  3.     p_owner IN VARCHAR2,
  4.     p_table_name IN VARCHAR2,
  5.     p_column_name IN VARCHAR2
  6.   ) RETURN NUMBER IS
  7.     l_cursor SYS_REFCURSOR;
  8.     l_clustering_factor BINARY_INTEGER := 0;
  9.     l_block_nr BINARY_INTEGER := 0;
  10.     l_previous_block_nr BINARY_INTEGER := 0;
  11.     l_file_nr BINARY_INTEGER := 0;
  12.     l_previous_file_nr BINARY_INTEGER := 0;
  13.   BEGIN
  14.     OPEN l_cursor FOR 'SELECT dbms_rowid.rowid_block_number(rowid) block_nr, ' ||
  15.      ' dbms_rowid.rowid_to_absolute_fno(rowid, ''' || p_owner || ''',''' || p_table_name || ''') file_nr ' ||
  16.       'FROM ' || p_owner || '.' || p_table_name || ' ' ||
  17.        'WHERE ' || p_column_name || ' IS NOT NULL ' || 'ORDER BY ' || p_column_name;
  18.        
  19.     LOOP
  20.     
  21.       FETCH l_cursor
  22.         INTO l_block_nr, l_file_nr;
  23.         
  24.       EXIT WHEN l_cursor%NOTFOUND;
  25.       
  26.       IF (l_previous_block_nr <> l_block_nr OR
  27.          l_previous_file_nr <> l_file_nr)
  28.       THEN
  29.         l_clustering_factor := l_clustering_factor + 1;
  30.       END IF;
  31.       
  32.       l_previous_block_nr := l_block_nr;
  33.       l_previous_file_nr := l_file_nr;
  34.       
  35.     END LOOP;
  36.     
  37.     CLOSE l_cursor;
  38.     RETURN l_clustering_factor;
  39.   END clustering_factor;
  40.   /

  SELECT clustering_factor('SCOTT', 'CLFTR_ANL', 'ID') cluster_factoring
  FROM   dual;
  --17
 
  SELECT clustering_factor('SCOTT', 'CLFTR_ANL', 'scatt') cluster_factoring
  FROM   dual;
  --340
/******************************************************************************/
--4.使用SYS_OP_COUNTCHG计算cluster_factoring,oracle未公布的内部函数,是dbms_stats
--低层调用:
 
  1):来自psoug的说明
 
SYS_OP_COUNTCHG
 Undocumented
SYS_OP_COUNTCHG(rowid, integer_between_1_and_255)
SELECT COUNT(DISTINCT dbms_rowid.rowid_block_number(rowid))
 FROM airplanes;
 SELECT sys_op_countchg(SUBSTRB(ROWIDTOCHAR("AIRPLANES".ROWID),1,15),1)
 FROM airplanes;
 EXPLAIN PLAN FOR
 SELECT COUNT(DISTINCT dbms_rowid.rowid_block_number(rowid))
 FROM airplanes;
 SELECT * FROM TABLE(dbms_xplan.display);
 EXPLAIN PLAN FOR
 SELECT sys_op_countchg(SUBSTRB(ROWIDTOCHAR("AIRPLANES".ROWID),1,15),1)
 FROM airplanes;
 SELECT * FROM TABLE(dbms_xplan.display);
-- note difference between SORT GROUP BY and SORT AGGREGATE
 

  2):抓取自10046中在收集索引统计信息时的sql片段
 

  1. SELECT /*+
  2.     cursor_sharing_exact
  3.     dynamic_sampling(0)
  4.     no_monitoring
  5.     no_expand
  6.     index(t,IND_CLFTR_ANL1)
  7.     noparallel_index(t,IND_CLFTR_ANL1)
  8.   */
  9.  sys_op_countchg(substrb(t.ROWID, 1, 15), 1) AS clf
  10. FROM clftr_anl t
  11. WHERE scatt IS NOT NULL;
  12. --340

/******************************************************************************/
--5.cluster_factoring对执行计划的影响
 
BEGIN
  dbms_stats.set_index_stats(ownname => USER,
                             indname => 'ind_clftr_anl1',
                             clstfct => 20);
END;
/
 
SELECT /*+index(t) gather_plan_statisitcs*/
 *
FROM   scott.clftr_anl t
WHERE  scatt IS NOT NULL;

------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Rows  | Bytes | Cost  |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                | 10000 | 60000 |    41 |
|   1 |  TABLE ACCESS BY INDEX ROWID| CLFTR_ANL      | 10000 | 60000 |    41 |
|*  2 |   INDEX FULL SCAN           | IND_CLFTR_ANL1 | 10000 |       |    21 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("SCATT" IS NOT NULL)
统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        365  consistent gets
          0  physical reads
          0  redo size
      90467  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)
      10000  rows processed
     
这里我们看到,autotrace输出的cost此时一定是不正确的,而真实可信的是365  consistent gets,
下面我们来看看真实运行时执行计划:
 
SELECT *
FROM   TABLE(dbms_xplan.display_cursor('a0m8kxd744871', 0, 'runstats_last'));
--------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------
|   1 |  TABLE ACCESS BY INDEX ROWID| CLFTR_ANL      |      1 |  10000 |  10000 |00:00:00.01 |     365 |
|*  2 |   INDEX FULL SCAN           | IND_CLFTR_ANL1 |      1 |  10000 |  10000 |00:00:00.01 |      23 |
--------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter("SCATT" IS NOT NULL)
  
/******************************************************************************/
  6.总结
 
  其实说了那么多,无非就是要提醒一点;即当使用dbms_stats收集的索引统计信息时,如果
clustering_factor被计算的很高,则此时可能要人为介入以给出一个合适的值,否则这个索引
在区间扫描时被使用的机率很低。
 
  那么在什么情况下我们可以适度的人为降低clustering factor呢?其实原则很简单,我们知道
如果clustering factor值很大,如果采用传统索引访问路径,则我们要在表的不同块之间反复切
换,而这些块可能都已经在内存中了,所以不存在io开销问题;对于内存块访问,最昂贵的开销莫
过于latch,而latch直接影响并发,所以如果你使用的是OLTP系统,则不建议你调整这个值,而
如果是DSS,OLAP系统,则可以适当的下调这个值的大小。
 
阅读(1060) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~