转 达梦统计信息和真实执行计划

https://www.cnblogs.com/fangzpa/p/16998683.html

 

达梦统计信息收集 及获取真实执行计划

 

1. 统计信息对执行计划的影响

达梦数据库是基于代价的优化器,达梦数据库统计信息不准,会影响到执行计划的估算,导致SQL解析到错误的执行计划

DROP TABLE IF EXISTS TEST;

CREATE TABLE TEST (EID INT PRIMARY KEY IDENTITY(1,1),ENAME VARCHAR(20),AGE INT,E_DATE DATE,SAL NUMBER(8,2),PHONE VARCHAR(20),DEPTNO INT);

--创建存储过程

CREATE OR REPLACE PROCEDURE P_TEST AS

DECLARE I INT;

BEGIN

FOR I IN 1..10000 LOOP

INSERT INTO TEST (ENAME,AGE,E_DATE,SAL,PHONE,DEPTNO)

SELECT DBMS_RANDOM.STRING('2',TRUNC(DBMS_RANDOM.VALUE(4,6))),

TRUNC(DBMS_RANDOM.VALUE(18,60)),

 ADD_DAYS(SYSDATE(),DBMS_RANDOM.VALUE(-10000,-10)),

 TRUNC(DBMS_RANDOM.VALUE(1000,50000),2),

TRUNC(DBMS_RANDOM.VALUE(13111111111,17999999999)),

TRUNC(DBMS_RANDOM.VALUE(1,10)) FROM DUAL;

END LOOP;

IF  MOD(I,500)=0 THEN

COMMIT;

END IF;

END;

--调用存储过程

CALL P_TEST;

--查看test表基数,根据需要选择过滤性大的字段建索引

select count(distinct ename) name,count(DISTINCT age) age ,count(distinct e_date) edate,count(DISTINCT sal) sal ,count(distinct phone)phone,count(distinct deptno)deptno from test;

 

CREATE INDEX IDX_TEST_ENAME ON TEST (ENAME);

CREATE INDEX IDX_TEST_HDATE ON TEST (E_DATE);

CREATE INDEX IDX_TEST_SAL ON TEST (SAL);

--查看表是否统计信息

SELECT TABLE_NAME,NUM_ROWS,LAST_ANALYZED,TEMPORARY  FROM USER_TABLES WHERE TABLE_NAME='TEST';

主要看NUM_ROWS字段,如果没有收集通常是空,第二个LAST_ANALYZED 代表收集的时间,如果没有收集这个字段也是空,第三个TEMPORARY字段附带说明,N表示不是临时表,Y表示是临时表,通常如果TEMPORARY=Y 是不用收集的

2. 客户端查看预估执行计划

通过客户端看到:当sal<5000和sal<10000时,客户端估算结果集都是500,当条件ENAME='ATCA'时,估算结果集是250

SELECT * FROM TEST WHERE SAL <5000;

 

SELECT * FROM TEST WHERE SAL <10000;

 

SELECT * FROM TEST WHERE ENAME='ATCA'

 

3. 获取真实执行计划

使用EXPLAIN语句可以查看sql的执行计划,但EXPLAIN只生成执行计划,并不会真正执行SQL语句,因此产生的执行计划有可能不准,下面可以通过几种方法获取真实执行计划,可以看到执行计划估算数据量和实际数据量,相差不大一般没有影响,如果比较大就要收集了,否则会影响性能

(1)执行set autotrace trace获取真实计划

--在服务器disql登录,查看上面真实执行计划

ALTER SESSION SET 'MONITOR_SQL_EXEC'=1;

set autotrace trace;

SELECT * FROM TEST WHERE SAL <5000;

--实际877,估算500

 

SELECT * FROM TEST WHERE SAL <10000;

--实际1811,估算500

 

SELECT * FROM TEST WHERE ENAME='ATCA'

--实际1,估算250

 

(2)v$cachepln中获取执行计划

v$cachepln中保存了SQL缓冲区中的执行计划信息,在ini参数USE_PLN_POOL !=0时才统计。根据v$cachepln中的cache_item可以获取实际执行计划信息

select * from v$cachepln where upper(sqlstr) like '%SELECT * FROM TEST WHERE ENAME%'

 

在 trace 目录中生成对应 trc 文件,查看文件里面的执行计划

 alter session set events 'immediate trace name plndump level 139718993205344,dump_file ''/dmdata/testcahe.log''';

 

(3)通过ET系统函数获取执行计划(主要看执行计划哪一步的执行最久)

--可通过配置参数中的ENABLE_MONITOR=1、MONITOR_TIME=1和MONITOR_SQL_EXEC=1开启两个参数均为动态参数,可直接调用系统函数进行修改

SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1);

SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',1);

--仅对当前会话有效

sf_set_session_para_value('MONITOR_SQL_EXEC',1);

 

4. 收集统计信息

--收集指定用户默认模式下统计信息

select 'DBMS_STATS.GATHER_SCHEMA_STATS('''||username||''',100,TRUE,''FOR  ALL COLUMNS SIZE AUTO'');' from all_users;

--注意:比如下面只是收集SYSDBA模式下面的统计信息,如果SYSDBA有多个模式,其他模式的统计信息是无法收集的

DBMS_STATS.GATHER_SCHEMA_STATS('SYSDBA',100,TRUE,'FOR  ALL COLUMNS SIZE AUTO');

--查看当前用户下有多少模式名

SELECT SCH_OBJ.NAME   SCHEMA_NAME,USER_OBJ.NAME USER_NAME

FROM( SELECT NAME, ID, PID, CRTDATE FROM SYS.SYSOBJECTS WHERE TYPE$='SCH')SCH_OBJ,

    (SELECT NAME, ID FROM SYS.SYSOBJECTS WHERE TYPE$='UR' AND SUBTYPE$='USER' ) USER_OBJ

WHERE SCH_OBJ.PID=USER_OBJ.ID AND USER_OBJ.NAME='SYSDBA' ORDER BY SCH_OBJ.NAME;

--收集TEST表统计信息

DBMS_STATS.GATHER_TABLE_STATS('SYSDBA','TEST',NULL,100,TRUE,'FOR ALL COLUMNS SIZE AUTO');

5. 收集统计信息之后看执行计划

收集统计信息之后,客户端执行计划估值值和实际值很准确了,但服务器真实执行计划还是以前老的执行计划,这是因为以前执行了这个sql,缓存了以前的执行计划。

--客户端执行计划

 

--服务器服务器trace真实执行计划

SELECT * FROM TEST WHERE SAL <5000

6. 清空缓存

--找到对应SQL 对应的 cache_item 值

select cache_item,sqlstr,'call sp_clear_plan_cache('||cache_item||');' from v$cachepln where sqlstr like '%表名%';

 

--根据cache_item 值,清空对应sql的缓存

call sp_clear_plan_cache(cache_item);---不加 pln 就是清理所有 sql 缓存

--清空缓存之后,真实执行计划已经正常了

 

 
好文要顶 关注我
posted @ 2023-12-14 14:41  feiyun8616  阅读(58)  评论(0编辑  收藏  举报