人工干预优化器的统计信息

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xxzhaobb/article/details/88551233

原文地址:https://docs.oracle.com/en/database/oracle/oracle-database/12.2/tgsql/controlling-the-use-of-optimizer-statistics.html#GUID-87A26DD9-E2C1-41E3-9EF0-D141F44F0968

设置优化器的统计信息,从而欺骗优化器,让优化器走不同的执行计划(这里有部分没有测试成功,文档上的未人工干预的时候,走的执行计划是全表扫描,测试还是走的索引,人工干预后,走的还是索引,不过优化器评估的rows有很大变化,了解了这个原理)。

- - 创建表和索引,并插入1条数据

BB@test>CREATE TABLE contractors (
con_id NUMBER,
last_name VARCHAR2(50),
salary NUMBER,
CONSTRAINT cond_id_pk PRIMARY KEY(con_id) );  2    3    4    5  

Table created.

BB@test>CREATE INDEX salary_ix ON contractors(salary);

Index created.

BB@test>INSERT INTO contractors VALUES (8, 'JONES',1000);

1 row created.

BB@test>commit;

Commit complete.

BB@test>

-- 收集统计信息,并查看统计信息情况

BB@test>EXECUTE DBMS_STATS.GATHER_TABLE_STATS( user, tabname => 'CONTRACTORS' );

PL/SQL procedure successfully completed.

BB@test>SELECT NUM_ROWS FROM USER_TABLES WHERE TABLE_NAME = 'CONTRACTORS';

  NUM_ROWS
----------
	 1

BB@test>SELECT NUM_ROWS FROM USER_INDEXES WHERE INDEX_NAME = 'SALARY_IX';

  NUM_ROWS
----------
	 1

-- 进行查询,查看执行计划

BB@test>SELECT /*+ dynamic_sampling(contractors 0) */ *
FROM contractors
WHERE salary = 1000;  2    3

    CON_ID LAST_NAME                                              SALARY
---------- -------------------------------------------------- ----------
         8 JONES                                                    1000

BB@test>SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID  dx4g7f3zzb3kk, child number 0
-------------------------------------
SELECT /*+ dynamic_sampling(contractors 0) */ * FROM contractors WHERE
salary = 1000

Plan hash value: 996794789

---------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |             |       |       |     2 (100)|          |

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| CONTRACTORS |     1 |    12 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | SALARY_IX   |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("SALARY"=1000)


20 rows selected.

BB@test>

-- 人工设置,将统计信息里面的行设置成2000,块10个,并查看统计信息,优化器认为有2000个行,10个块。

BB@test>BEGIN
DBMS_STATS.SET_TABLE_STATS(
ownname => user
, tabname => 'CONTRACTORS'
, numrows => 2000
, numblks => 10 );
END;  2    3    4    5    6    7  
  8  /

PL/SQL procedure successfully completed.

BB@test>BEGIN
DBMS_STATS.SET_INDEX_STATS(
ownname => user
, indname => 'SALARY_IX'
, numrows => 2000 );
END;  2    3    4    5    6  
  7  /

PL/SQL procedure successfully completed.

BB@test>SELECT NUM_ROWS FROM USER_TABLES WHERE TABLE_NAME = 'CONTRACTORS';

  NUM_ROWS
----------
      2000

BB@test>SELECT NUM_ROWS FROM USER_INDEXES WHERE INDEX_NAME = 'SALARY_IX';

  NUM_ROWS
----------
      2000

BB@test>

--
BB@test>ALTER SYSTEM FLUSH SHARED_POOL;

System altered.

BB@test>SELECT /*+ dynamic_sampling(contractors 0) */ *
FROM contractors
WHERE salary = 1000;  2    3


Execution Plan
----------------------------------------------------------
Plan hash value: 996794789

---------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |             |  2000 | 24000 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| CONTRACTORS |  2000 | 24000 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | SALARY_IX   |  2000 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

-- 删除掉统计信息

BB@test>exec dbms_stats.delete_table_stats(user,'CONTRACTORS');

PL/SQL procedure successfully completed.

-- 虽然未测试成功,但原理已了解。

end

猜你喜欢

转载自blog.csdn.net/xxzhaobb/article/details/88551233