oracle的pending事务,Oracle 11g 数据统计量Pending处理

在CBO时代,SQL语句的执行计划完全依赖于在数据字典中保存的统计量信息和优化器Optimizer的计算公式参数。从9i开始到现在的11gR2,我们说CBO优化器已经很成熟和完善。在通常情况下,我们的SQL都是可以获取到较好的执行计划以及执行效率的。

在实际工作中,我们经常会遇到执行计划低效的情况。但是这种故障根源中,绝大多数的原因在于统计量的错误或者失效。错误的统计量连带生成的就是不恰当的执行计划,以至于低效的执行过程。在9i时代,RBO和CBO混合使用,让我们经常需要自定义的统计量收集过程。

从10g开始,Oracle引入了自动收集统计量的作业,以保证数据字典中统计量正确反映数据对象状态。这在很大程度上,缓解了由于数据变化导致的统计量过期问题。但是,我们在实际工作中,还是会发现执行计划的突然变化。究其原因,就是某个时间点收集的统计量,也许不能反映数据的全貌(如中间表)。

在系统运维中,我们常常希望维持SQL执行计划的稳定。很多DBA和开发人员对于hint的依赖,很大程度上也是源于对CBO情况下,执行计划对于统计量过于依赖,容易形成不稳定执行计划。

那么,我们SQL语句执行计划的稳定性,就变成统计量的稳定性问题。更进一步,就是新的统计量更新,无论是否手动收集还是自动收集,能否促进SQL语句生成更高效的执行计划。

所以,一种思路是:在新的统计量收集生成时,暂时不要生效投入执行计划生成。等待最后确认统计量正确之后,再投入生产环境。

在Oracle 11g中,推出了统计量管理的一种新技术——Pending Statistic技术,提供了这种功能。

简单的说,我们可以对一系列的数据表设置pending属性。设置pending属性之后,数据的统计量在数据字典中相当于已经锁定Lock住。但新统计量生成之后,不是直接替换原有的数据,而是存放在pending数据字典中。

在pending字典中的统计量,默认情况下是不会参与SQL执行计划的生产的。只有在进行SQL测试通过的时候,经过用户手工的确定,才会将其Publish出来,替换原有的统计量信息。

这样,就给我们运维DBA一种维持执行计划稳定的思路。通过固定统计量,将新统计量pending的方式将原有的统计量固定,从而稳定执行计划。进而,对pending的统计量进行测试,只有在更好执行计划的情况下,才会替换原有的方案。

下面,我们通过实验来验证pending统计量的使用。

2、实验环境构建

我们选择11gR2进行实验。

SQL> select * from v$version;

BANNER

-----------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE11.2.0.1.0Production

构建数据表T,以及对应的索引。注意,我们首先在数据表中不保存任何数据。

SQL> create table t as select * from dba_objects where 1=0;

Table created

SQL> create index idx_t_owner on t(owner);

Index created

SQL> create index idx_t_id on t(object_id);

Index created

在不显式的收集统计量的情况下,是没有对应的数据表统计量的。

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKSAVG_SPACECHAIN_CNT AVG_ROW_LEN

---------- ------------ ---------- ---------- -----------

SQL> select count(*) from user_tab_col_statistics where table_name='T';

COUNT(*)

----------

0

SQL> select BLEVEL, LEAF_BLOCKS, DISTINCT_KEYS, CLUSTERING_FACTORNUM_ROWS from user_ind_statistics where index_name='IDX_T_OWNER';

BLEVEL LEAF_BLOCKS DISTINCT_KEYSNUM_ROWS

---------- ----------- ------------- ----------

0000

收集统计量,获取最新的数据分布状况。

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

当我们修改数据内容,没有收集统计量,会存在新旧差异。

SQL> insert into t select * from dba_objects;

72202 rows inserted

SQL> commit;

Commit complete

SQL>select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKSAVG_SPACECHAIN_CNT AVG_ROW_LEN

---------- ------------ ---------- ---------- -----------

00000

3、Pending Statistics设置

在11g环境中,数据表、Schema都存在一个统计量相关参数PUBLISH,表示当有新统计量的时候,新统计量是否立即被publish出来,作为最新的统计信息使用。

该参数的默认值为TRUE。

SQL> select dbms_stats.get_prefs(pname => 'PUBLISH',ownname => 'SYS',tabname => 'T') from dual;

DBMS_STATS.GET_PREFS(PNAME=>'P

-------------------------------------------------------

TRUE

--设置数据表的publish参数取值;

SQL> exec dbms_stats.set_table_prefs(user,'T','PUBLISH','false');

PL/SQL procedure successfully completed

SQL> select dbms_stats.get_prefs('PUBLISH',ownname => 'SYS',tabname => 'T') from dual;

DBMS_STATS.GET_PREFS('PUBLISH'

--------------------------------------

FALSE

此时,数据表中已经包括了七万余条数据,重新收集统计量。

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKSAVG_SPACECHAIN_CNT AVG_ROW_LEN

---------- ------------ ---------- ---------- -----------

00000

当我们将数据表T的PUBLISH参数修改为false之后,我们重新收集统计量,发现原有统计信息并没有连带的更新。

新统计量不是没有收集,而是被记录在了pending信息中。我们可以通过user_ind_pending_stats和user_tab_pending_stats两个视图查看被pending的统计量信息。

SQL> select NUM_ROWS, BLOCKS, AVG_ROW_LEN, SAMPLE_SIZE, LAST_ANALYZED from user_tab_pending_stats where table_name='T';

NUM_ROWSBLOCKS AVG_ROW_LEN SAMPLE_SIZE LAST_ANALYZED

---------- ---------- ----------- ----------- -------------

7220210289772202 2012/6/20 20:

SQL> select index_name, LEAF_BLOCKS, DISTINCT_KEYS, CLUSTERING_FACTOR,LAST_ANALYZED from user_ind_pending_stats where table_name='T';

INDEX_NAMELEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR LAST_ANALYZED

------------------------------ ----------- ------------- ----------------- -------------

IDX_T_OWNER293231884 2012/6/20 20:

IDX_T_ID256722021665 2012/6/20 20:

4、Pending和SQL执行计划

新的统计量没有被publish出来。那么,在一般情况下,我们的SQL执行计划还是依据正式被publish的统计量生成。

SQL> explain plan for select * from t where wner='SYS';

Explained

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

------------------------------------------------------------------------------

Plan hash value: 1516787156

------------------------------------------------------------------------------

| Id| Operation| Name| Rows| Bytes | Cost (%CPU)|

-------------------------------------------------------------------------------

|0 | SELECT STATEMENT||1 |207 |1(0)|

|1 |TABLE ACCESS BY INDEX ROWID| T|1 |207 |1(0)|

|*2 |INDEX RANGE SCAN| IDX_T_OWNER |1 ||1(0)|

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("OWNER"='SYS')

14 rows selected

实际执行情况;

SQL> select * from t where wner='SYS';

已选择58799行。

已用时间:00: 00: 06.19

执行计划

----------------------------------------------------------

Plan hash value: 1516787156

-------------------------------------------------------------------------------

| Id| Operation| Name| Rows| Bytes | Cost (%CPU)| Time|

---------------------------------------------------------------------------------------

|0 | SELECT STATEMENT||1 |207 |1(0)| 00:00:01 |

|1 |TABLE ACCESS BY INDEX ROWID| T|1 |207 |1(0)| 00:00:01 |

|*2 |INDEX RANGE SCAN| IDX_T_OWNER |1 ||1(0)| 00:00:01 |

-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("OWNER"='SYS')

统计信息

----------------------------------------------------------

528recursive calls

0db block gets

8962consistent gets

1108physical reads

0redo size

6291375bytes sent via SQL*Net to client

43520bytes received via SQL*Net from client

3921SQL*Net roundtrips to/from client

4sorts (memory)

0sorts (disk)

58799rows processed

SQL>

在sys用户下,行数比例超过了数据表T的绝大多数。按照CBO的原则,走全表扫描可能是较好的方法。但是,由于统计量还是在空表的状态下,所以,Oracle CBO认为Index路径会更好。

在Oracle中,存在一个参数optimizer_use_pending_statistics,用来控制当前是否使用pending的统计量来生成执行计划。作为运维DBA,可以通过这个参数暂时性的启用pending统计量,观察一下性能状况。再决定是否启用publish这些统计量。

默认情况下,该参数取值为false。我们可以在session级别设置下该参数为true。

SQL> show parameter optimizer_use_pending

NAMETYPEVALUE

------------------------------------ ----------- ------------------------------

optimizer_use_pending_statisticsbooleanFALSE

修改参数为true之后,Oracle CBO在生成执行计划的时候就会使用Pending的统计量。

SQL> alter session set optimizer_use_pending_statistics=true;

Session altered

SQL> select value from v$parameter where name='optimizer_use_pending_statistics';

VALUE

------------------------------------------

TRUE

SQL> explain plan for select * from t where wner='SYS';

Explained

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------

Plan hash value: 1601196873

--------------------------------------------------------------------------

| Id| Operation| Name | Rows| Bytes | Cost (%CPU)| Time|

--------------------------------------------------------------------------

|0 | SELECT STATEMENT|| 58274 |5463K|281(1)| 00:00:04 |

|*1 |TABLE ACCESS FULL| T| 58274 |5463K|281(1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("OWNER"='SYS')

13 rows selected

SQL> select * from t where wner='SYS';

已选择58799行。

已用时间:00: 00: 04.68

执行计划

----------------------------------------------------------

Plan hash value: 1601196873

--------------------------------------------------------------------------

| Id| Operation| Name | Rows| Bytes | Cost (%CPU)| Time|

--------------------------------------------------------------------------

|0 | SELECT STATEMENT|| 58274 |5463K|281(1)| 00:00:04 |

|*1 |TABLE ACCESS FULL| T| 58274 |5463K|281(1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("OWNER"='SYS')

统计信息

----------------------------------------------------------

7511recursive calls

50db block gets

6599consistent gets

1118physical reads

0redo size

2392962bytes sent via SQL*Net to client

43520bytes received via SQL*Net from client

3921SQL*Net roundtrips to/from client

211sorts (memory)

0sorts (disk)

58799rows processed

果然,设置参数后,Oracle生成了FTS路径,说明更新的统计量起了作用。同时,执行时间减少了近2秒钟,说明结果上也确实是生成了更好的执行计划。

5、Pending统计量的后续处理

在对pending统计量进行合理评估之后,DBA是可以做出删除还是发布统计量的决定的。具体操作如下:

--删除pending信息

SQL> exec dbms_stats.delete_pending_stats(user,'T');

PL/SQL procedure successfully completed

SQL> select count(*) from user_tab_pending_stats;

COUNT(*)

----------

0

--重新收集pending统计量

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKSAVG_SPACECHAIN_CNT AVG_ROW_LEN

---------- ------------ ---------- ---------- -----------

00000

--发布pending统计量

SQL> exec dbms_stats.publish_pending_stats(user,'T');

PL/SQL procedure successfully completed

SQL> select NUM_ROWS, BLOCKS EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN from user_tab_statistics where table_name='T';

NUM_ROWS EMPTY_BLOCKSAVG_SPACECHAIN_CNT AVG_ROW_LEN

---------- ------------ ---------- ---------- -----------

7220210280096

单发布完统计量之后,就可以在正常的情况下使用统计量生成执行计划了。

SQL> show parameter optimizer_use_pen

NAMETYPEVALUE

------------------------------------ ----------- ------------------------------

optimizer_use_pending_statisticsbooleanFALSE

SQL> alter session set optimizer_use_pending_statistics=false;

会话已更改。

已用时间:00: 00: 00.01

SQL> select * from t where wner='SYS';

已选择58799行。

已用时间:00: 00: 04.33

执行计划

----------------------------------------------------------

Plan hash value: 1601196873

--------------------------------------------------------------------------

| Id| Operation| Name | Rows| Bytes | Cost (%CPU)| Time|

--------------------------------------------------------------------------

|0 | SELECT STATEMENT|| 58794 |5511K|281(1)| 00:00:04 |

|*1 |TABLE ACCESS FULL| T| 58794 |5511K|281(1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("OWNER"='SYS')

统计信息

----------------------------------------------------------

426recursive calls

0db block gets

4975consistent gets

0physical reads

0redo size

2392962bytes sent via SQL*Net to client

43520bytes received via SQL*Net from client

3921SQL*Net roundtrips to/from client

4sorts (memory)

0sorts (disk)

58799rows processed

6、结论

在11g中提出的pending statistic的方法,可以在生产运维和稳定优化执行计划方面,给我们提供帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要释放Oracle 11g中的undo表空间,可以按照以下步骤操作: 1. 首先,确认当前undo表空间的使用情况,可以使用以下命令查询: SELECT tablespace_name, sum(bytes)/1024/1024 "Size (MB)", sum(maxbytes)/1024/1024 "Max Size (MB)" FROM dba_data_files WHERE tablespace_name = 'UNDOTBS1' GROUP BY tablespace_name; 其中,'UNDOTBS1'为当前使用的undo表空间名称。 2. 确认当前没有任何事务在进行中,可以使用以下命令查询: SELECT COUNT(*) FROM v$transaction; 如果返回结果为0,则表示当前没有事务在进行中。 3. 执行以下命令释放undo表空间: ALTER SYSTEM CHECKPOINT; ALTER SYSTEM SET UNDO_RETENTION=0; ALTER TABLESPACE UNDOTBS1 OFFLINE IMMEDIATE; DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES; 其中,'UNDOTBS1'为当前使用的undo表空间名称。 4. 最后,确认undo表空间已经释放,可以使用以下命令查询: SELECT tablespace_name, status FROM dba_tablespaces WHERE tablespace_name = 'UNDOTBS1'; 如果返回结果为'PENDING OFFLINE',则表示undo表空间已经成功释放。 注意:释放undo表空间可能会导致数据丢失,请谨慎操作。建议在备份数据后再进行操作。 ### 回答2: 当Oracle数据库中的Undo表空间(也称为回滚段)不再使用时,它可以被释放以节省磁盘空间。在Oracle 11g中,可以按照以下步骤来释放Undo表空间: 1. 确定未使用的Undo表空间:首先需要确定哪些Undo表空间未使用。可以通过查询v$undostat视图来获取当前的Undo表空间使用情况。该视图提供有关Undo表空间大小、使用、可用等等信息。 2. 切换所有事务到新Undo表空间:在释放旧的Undo表空间之前,需要将所有正在运行的事务切换到新的Undo表空间中。可以通过以下方法创建一个新的Undo表空间: CREATE UNDO TABLESPACE new_undo_ts DATAFILE '/path/to/new_undo_ts.dbf' SIZE 10G; ALTER SYSTEM SET UNDO_TABLESPACE=new_undo_ts SCOPE=SPFILE; SHUTDOWN IMMEDIATE; STARTUP; 在创建新的Undo表空间之后,需要将所有正在使用旧Undo表空间的事务切换到新的Undo表空间中。可以使用以下命令来完成: ALTER SYSTEM SET UNDO_TABLESPACE=new_undo_ts; 3. 等待Undo表空间变为闲置状态:在切换所有事务到新Undo表空间之后,需要等待旧的Undo表空间变为闲置状态。可以通过查询v$rollstat视图来检查它的状态。当状态更改为“NEEDS_COMPACT”时,就开始可以释放旧的Undo表空间了。 4. 释放Undo表空间:使用以下命令释放Undo表空间: ALTER TABLESPACE old_undo_ts OFFLINE; DROP TABLESPACE old_undo_ts INCLUDING CONTENTS AND DATAFILES; 此时,“old_undo_ts”是要释放的Undo表空间的名称。 总之,在释放Undo表空间之前,需要确保所有活动的事务切换到新的Undo表空间中,并且该Undo表空间处于“闲置”状态。释放Undo表空间应该是仔细计划和谨慎实施的过程。 ### 回答3: 当Oracle 11g释放undo表空间时,需要遵循以下步骤: 1. 确认undo表空间已经没有任何无需保留的信息。可以通过检查v$rollstat动态视图、使用SQL查询语句或运行Oracle标准性能分析工具来查看当前undo空间的使用情况。 2. 执行回滚段清理,并确保没有任何未提交的事务或会话进行操作。可以使用以下语句进行回滚段清理: ALTER SYSTEM CHECKPOINT; 3. 确定当前正在使用的回滚段及其数据文件。可以使用以下语句来查询当前正在使用的回滚段: SELECT segment_name, tablespace_name FROM dba_rollback_segs WHERE status = 'USABLE' AND tablespace_name = '&tablespace_name'; 4. 更改所有正在使用的回滚段的表空间为新的undo表空间。可以使用以下语句来更改表空间: ALTER ROLLBACK SEGMENT &segment_name ONLINE; ALTER ROLLBACK SEGMENT &segment_name STORAGE (TABLESPACE &new_tablespace); 5. 删除所有旧的undo表空间。可以使用以下语句来删除表空间: DROP TABLESPACE &old_tablespace INCLUDING CONTENTS AND DATAFILES; 需要注意的是,释放undo表空间不会发生立即效果,因为Oracle在使用undo信息时会将其添加到其内部事务表中,所以要等待所有当前执行的事务完成并更新内部事务表后,才能彻底释放undo表空间。同时,释放undo表空间也要谨慎操作,以免影响数据库的稳定性和数据完整性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值