Oracle 12c New Feature: 臨時表(global temporary table

分類:IT技術 時間:2017-02-22

有時我們會在應用程序中用到數據庫全局臨時表(global temporary tables)用於存放臨時的數據集, 在12c之前對於全局臨時表上的統計信息處理非常的棘手, 就像我之前的一篇案例( 臨時表不要收統計信息 )中遇到的, 當時建議是不對臨時表收集統計信息解決方案, 讓數據庫使用動態采樣來估算實際表中的數據, 因為臨時表對所有用戶可見,但數據只對當前的用戶可見,數據保留分事務級和會話級, 除了動態采樣外也可以使用hint固定或者使用dbms_stats表set一個更佳接近實際數據的值以生成正確執行計劃. 以前就想過CBO應該改進對於GTT的統計信息收集的方法,後來發現在12c中Oracle已經解決了這個問題.

在12C以前oracle不會主動維護全局臨時表(global temporary tables)的統計信息, 並且如果手動收集也只是存在一份統計信息,即使不同的會話級臨時表的數據量不一致,一旦存在對所有的會話可見,從12.1起可以使用GLOBAL_TEMP_TABLE_STATS 控制GTT表的統計信息是所有會話共享還是session級私有,默認session級統計信息是啟用的. CBO 在查看表的統計信息時順序是先看當前session級是否存在統計信息,如果沒有再使用共享的統計信息(如果存在), 這樣在dba_tab_statistics表中一個臨時表就可能存在一個共享統計信息和一個session級統計信息記錄, 以scope字段做區分.

另外註意在12c前如果臨時表數據是事務級(on commit delete rows)在做dbms_stats收集表統計信息時會先隱性的發起一個commit, 最終臨時表的記錄為0, 而在12C中則不會刪除記錄.與該特性相關的隱藏參數是_optimizer_use_gtt_session_stats, default值為true. 該特性對SYS無效,測試請使用其他用戶,下面演示一下這個特性.

12C以前的版本的不再演示, 如果收集了臨時表統計信息, 所有會話使用相同的統計信息,可能產生錯誤的執行計劃.

SQL> select * from v$version;

BANNER                                                                               CON_ID
-------------------------------------------------------------------------------- ----------
Oracle Database 12c EE Extreme Perf Release 12.2.0.1.0 - 64bit Production                 0
PL/SQL Release 12.2.0.1.0 - Production                                                    0
CORE    12.2.0.1.0      Production                                                        0
TNS for Linux: Version 12.2.0.1.0 - Production                                            0
NLSRTL Version 12.2.0.1.0 - Production                                                    0


驗證當前默認臨時表stat scope
SQL> SELECT DBMS_STATS.get_prefs('GLOBAL_TEMP_TABLE_STATS') FROM dual;

DBMS_STATS.GET_PREFS('GLOBAL_TEMP_TABLE_STATS')
-------------------------------------
SESSION

如果想修改為共享方法
BEGIN
  DBMS_STATS.set_global_prefs (
    pname   => 'GLOBAL_TEMP_TABLE_STATS',
    pvalue  =http://ju.outofmemory.cn/entry/>'SHARED');
END;
/

SQL> show pdbs
    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
 PDB$SEED                       READ ONLY  NO
 PDBANBOB                       READ WRITE NO
		 
		 
oracle@anbob ~]$ export TWO_TASK=pdbanbob
[oracle@anbob ~]$ sqlplus anbob/anbob     

SQL*Plus: Release 12.2.0.1.0 Production on Tue Feb 21 16:45:47 2017
Copyright (c) 1982, 2016, Oracle.  All rights reserved.
Last Successful login time: Mon Feb 20 2017 21:32:52 +08:00
Connected to:
Oracle Database 12c EE Extreme Perf Release 12.2.0.1.0 - 64bit Production

SQL> create global temporary table GTT(id int, name varchar2(20)) on commit preserve rows;
Table created.

SQL> select DBMS_STATS.GET_PREFS('GLOBAL_TEMP_TABLE_STATS','ANBOB','GTT') FROM DUAL;
DBMS_STATS.GET_PREFS('GLOBAL_TEMP_TABLE_STATS','ANBOB','GTT')
--------------------------------------------------------------------------------
SESSION

SQL> insert into gtt 
    select rownum,'anbob'||rownum from dual   connect by rownum<=1e6; 
000 rows created. 

SQL> commit;
Commit complete.

SQL> select  TABLE_NAME, BLOCKS,NUM_ROWS, SCOPE from USER_TAB_STATISTICS where TABLE_NAME = 'GTT';
TABLE_NAME               BLOCKS   NUM_ROWS SCOPE
-------------------- ---------- ---------- -------
GTT                                        SHARED

SQL> @gts gtt
Gather Table Statistics for table gtt...
PL/SQL procedure successfully completed.

SQL> select  TABLE_NAME, BLOCKS,NUM_ROWS, SCOPE from USER_TAB_STATISTICS where TABLE_NAME = 'GTT';
TABLE_NAME               BLOCKS   NUM_ROWS SCOPE
-------------------- ---------- ---------- -------
GTT                                        SHARED
GTT                        3018    1000000 SESSION

收集共享統計信息的方法
SQL> BEGIN
    DBMS_STATS.set_global_prefs (
      pname   => 'GLOBAL_TEMP_TABLE_STATS',
      pvalue  =http://ju.outofmemory.cn/entry/>'SHARED');
  END;
  /
PL/SQL procedure successfully completed.

SQL> @gts gtt
Gather Table Statistics for table gtt...
PL/SQL procedure successfully completed.

SQL> select  TABLE_NAME, BLOCKS,NUM_ROWS, SCOPE from USER_TAB_STATISTICS where TABLE_NAME = 'GTT';
TABLE_NAME               BLOCKS   NUM_ROWS SCOPE
-------------------- ---------- ---------- -------
GTT                        3018    1000000 SHARED
GTT                        3018    1000000 SESSION

SQL> set autot trace exp
SQL> select /*+ gather_plan_statistics */ * from gtt;

Execution Plan
----------------------------------------------------------
Plan hash value: 917624683

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1000K|    16M|   824   (1)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| GTT  |  1000K|    16M|   824   (1)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
   - Global temporary table session private statistics used
   

# SESSION 2

SQL> BEGIN
    DBMS_STATS.set_global_prefs (
      pname   => 'GLOBAL_TEMP_TABLE_STATS',
      pvalue  =http://ju.outofmemory.cn/entry/>'SESSION');
  END;
  /

PL/SQL procedure successfully completed.

[oracle@anbob ~]$ sqlplus anbob/anbob

SQL*Plus: Release 12.2.0.1.0 Production on Tue Feb 21 16:56:23 2017
Copyright (c) 1982, 2016, Oracle.  All rights reserved.

Last Successful login time: Tue Feb 21 2017 16:45:47 +08:00

Connected to:
Oracle database 12c EE Extreme Perf Release 12.2.0.1.0 - 64bit Production

SQL> select * from gtt;
no rows selected

SQL> insert into gtt 
      select rownum,'anbob'||rownum from dual   connect by rownum<=10; 
 rows created. 

SQL> @gts gtt
Gather Table Statistics for table gtt...
PL/SQL procedure successfully completed.

SQL> select  TABLE_NAME, BLOCKS,NUM_ROWS, SCOPE from USER_TAB_STATISTICS where TABLE_NAME = 'GTT';

TABLE_NAME                         BLOCKS   NUM_ROWS SCOPE
------------------------------ ---------- ---------- -------
GTT                                  3018    1000000 SHARED
GTT                                     1         10 SESSION

SQL> set autot trace exp
SQL> select /*+ gather_plan_statistics */ * from gtt;

Execution Plan
----------------------------------------------------------
Plan hash value: 917624683

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    10 |   100 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| GTT  |    10 |   100 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------

Note
-----
   - Global temporary table session private statistics used

Note:
現在可以看到在不同的session級, 查看執行計劃使用了session級專有的統計信息, 這樣在與其它表關連時不會再像12c以前的版本那樣使用錯誤的cardinality而造成產生錯誤的執行計劃. 並且在使用auto trace或使用dbmt_xplan查看執行計劃時會有”Global temporary table session private statistics used“的提示, 同時會註意到在session之間相同的sql使用自己新生成的SQL child cursor. 查看沒有共享的原因是”Session Specific Cursor Session Mismatch”

SQL> @sqlt gtt

HASH_VALUE SQL_ID             CHLD# OPT_MODE   SQL_TEXT
---------- ------------- ---------- ---------- --------------------------------------------------------
79998 cswbnusftyn0y          0 ALL_ROWS   select /*+ gather_plan_statistics */ * from gtt
79998 cswbnusftyn0y          1 ALL_ROWS   select /*+ gather_plan_statistics */ * from gtt
 rows selected.


SQL> @nonshared2 print cswbnusftyn0y

SQL_ID        CHILD#     REASON                                          REASON_XML
------------- ---------- ----------------------------------------------- --------------------------------------------------------------
cswbnusftyn0y 0          Session Specific Cursor Session Mismatch(1):    


                                                                         Session Specific Cursor Session Mismatch(1)
x2


3




          Session Specific Cursor Session Mismatch(1):    


                                                                         Session Specific Cursor Session Mismatch(1)
x2





3

                                                                         

Summary:
在12c以前如果臨時表收集的統計信息可能與實際數據不一致時可能因為錯誤的CARD值CBO產生了錯誤的執行計劃, 從12C引入了session specific statistics, 這樣就解決了不同的會話之間數據差異而使用不同的統計信息, 避免cardinality的錯誤, 該特性從12C中默認是啟動的.


Tags: 解決方案 應用程序 oracle Oracle commit

文章來源:


ads
ads

相關文章
ads

相關文章

ad