1. 程式人生 > >Oracle擴展的統計信息

Oracle擴展的統計信息

函數 test 取值 函數轉換 combine 虛擬列 efault ext span

我們在收集列的統計信息與直方圖時,往往都是對某一列的收集。當謂詞使用多個相關列時,會導致約束條件的冗余。這幾個相關的列也被稱作關聯列。出現這種情況時,查詢優化器也會做出不準確的判斷。所以我們必須對這些相關列收集統計信息或直方圖來描述這種依賴關系。

幸運的是,從Oracle11g開始,數據庫可以收集基於表達式或者一組列上的對象統計信息和直方圖,從而解決這種問題。這種新的統計叫做擴展的統計信息(extension statistics)。

這種技術實際上是基於表達式或一組列創建一個隱藏列,叫做擴展(extension),再在擴展列上收集統計信息與直方圖。

一、如何定義擴展列

可以調用Oracle自帶的包dbms_stats的函數create_extended_stats來實現。下面對測試表的相關列做擴展列。測試表語句參見《Oracle中收集表與列統計信息》(http://www.linuxidc.com/Linux/2013-12/93503.htm)一個基於表達式upper(pad),另一個基於val2和val3組成的列組。在測試表裏,val2和val3取值相同,高度關聯。

SELECT DBMS_STATS.CREATE_EXTENDED_STATS(OWNNAME  => TEST,
                                        TABNAME  => T,
                                        EXTENSION => (upper(pad))),
      DBMS_STATS.CREATE_EXTENDED_STATS(OWNNAME  => TEST,
                                        TABNAME  
=> T, EXTENSION => (val2,val3)) FROM DUAL;

這樣就定義了兩個擴展列。他們分別是基於表達式的和基於多列的。

二、如何查詢擴展列信息

基於user_stat_extensions、dba_stat_extensions和all_stat_extensions,都能查詢相關的擴展列信息。

SELECT COLUMN_NAME, DATA_TYPE, HIDDEN_COLUMN, DATA_DEFAULT
  FROM USER_TAB_COLS
 
WHERE TABLE_NAME = T; COLUMN_NAME DATA_TYPE HID DATA_DEFAULT ---------------------------------------- ---------- --- ---------------------------------------- ID NUMBER NO VAL1 NUMBER NO VAL2 NUMBER NO VAL3 NUMBER NO PAD VARCHAR2 NO SYS_STU0KSQX64#I01CKJ5FPGFK3W9 VARCHAR2 YES UPPER("PAD") SYS_STUPS77EFBJCOTDFMHM8CHP7Q1 NUMBER YES SYS_OP_COMBINED_HASH("VAL2","VAL3")

從data_default這列我們可以觀察到,SYS_OP_COMBINED_HASH("VAL2","VAL3"),擴展列統計使用了哈希函數,所以val2和val3只有使用相等(=)謂詞時,優化器才使用擴展統計信息。

二、如何刪除擴展統計信息

依然使用Oracle自帶的dbms_stats提供的過程drop_extended_stats來刪除擴展統計信息。

BEGIN
  DBMS_STATS.DROP_EXTENDED_STATS(OWNNAME  => TEST,
                                TABNAME  => T,
                                EXTENSION => (upper(pad)));
  DBMS_STATS.DROP_EXTENDED_STATS(OWNNAME  => TEST,
                                TABNAME  => T,
                                EXTENSION => (val2,val3));
END;

最後提一下,擴展統計信息是基於Oracle11g的另一個新特性——虛擬列。它並不存儲數據,那它有什麽現實意義呢?我們可以設想,在開發代碼中,有很多sql語句用到了upper(varchar2)、trunc(date),此時盡管在這些列上建立索引,執行計劃依然不會走索引,為了避免全表掃描,我們最好的方法是改寫語法,謂詞盡量不被函數轉換,但有時候在不好轉換語句時,可以創建一個虛擬列,然後在虛擬列上建立索引。比如下面的方法:

CREATE TABLE persons(
NAME VARCHAR2(100),
name_upper AS (UPPER(NAME)));

如果在頻繁查詢使用了upper(name)=’MIKE’,就可以使用name_upper=’MIKE’,前提是虛擬列建立索引。當然虛擬列也不不好的地方,比如插入數據不能指定所有列,因為虛擬列是不存數據的。

Oracle擴展的統計信息