您的統計信息是否陳舊?不要再等待了
?
??? 大部分DBA都知道,Oracle 10g 版本最后不再支持(而不是反對)基于規則的優化器 (RBO)。考慮到這種期待已久的發展即將發生,很多 Oracle9i 數據庫商店升級到基于開銷的優化器 (CBO),以便進入支持循環并利用查詢重寫和分區修剪等高級特性。但是,問題在于統計信息 — 或者說在于缺少統計信息。
?
??? 因為 CBO 依靠準確的(或者說比較準確的)統計信息來產生優化的執行路徑,所以 DBA 需要確保定期收集統計信息,創建另一個執行核對清單。在 10g 之前,這一過程可能由于多種原因而徒勞無功。這種困難導致產生了一種理論,即 CBO 具有“自己的思想” — 這意味著會有隨意更改執行路徑的行為!
?
??? 在 10g 中已經消除了很多這類的顧慮,它能夠自動收集統計信息。在 Oracle9i 中,您可以通過打開表監視選項 (ALTER TABLE ...MONITORING) 然后檢查這些表的視圖 DBA_TAB_MODIFICATIONS,檢查表中的數據是否已明顯更改過。
?
??? 在 10g 中,已不再使用 MONITORING 語句了。而通過設置初始化參數 STATISTICS_LEVEL 為 TYPICAL 或 ALL,就可以自動收集統計信息。(默認值為 TYPICAL,因此可以隨即啟用自動收集統計信息的功能。)Oracle 數據庫 10g 具有一個預定義的調度程序(您在第 19 周中已經學習過調度程序)作業,名稱為 GATHER_STATS_JOB,它由 STATISTIC_LEVEL 參數的適當數值所激活。
?
??? 統計信息的收集是資源相當密集的工作,因此您可能希望確保它不影響數據庫的正常操作。在 10g 中,您可以使這一工作自動完成:可對一個名為 AUTO_TASK_CONSUMER_GROUP 的特定資源用戶組進行預定義,用于自動執行一些任務,比如收集統計信息。該用戶組確保這些統計信息收集作業的優先權低于默認用戶組,因此減少或消除了自動化任務占用整個機器的風險。
?
??? 如果希望將參數 STATISTIC_LEVEL 設為 TYPICAL 卻不希望自動收集統計信息時該怎么辦?很簡單。只需使用以下語句來禁用調度程序作業即可:
?
BEGIN
DBMS_SCHEDULER.DISABLE('GATHER_STATS_JOB');
END;
??? 那么您為什么要這樣做呢?有很多原因 — 其中一個原因是,雖然表中大部分行發生了變化,但分布情況可能沒有改變,這在數據倉庫中很常見。在這種情況下,您不希望再次收集統計信息,而只是希望重用原來的統計信息。另一個原因可能是您正在使用分區交換功能來刷新物化視圖 (MV),并且不希望收集關于物化視圖的統計信息,因為關于被交換表的統計信息也會被導入。但是,您也可以將特定的表排除在自動統計信息收集作業之外,而不需要禁止整個作業。
?
?
統計信息歷史
?
??? 在優化器收集統計信息時可能出現的復雜情況之一是執行計劃的改變 — 也就是說,原來的優化方法在收集統計信息之前一直工作良好,但是在此之后,由于新收集的統計信息產生了不良計劃,導致查詢突然出錯。這種問題并不少見。
?
??? 為避免這種災難,統計信息的收集作業在收集新信息之前保存當前的統計信息。如果出現問題,您總可以返回到原有的統計信息,或者至少可以檢查二者之間的不同之處,以便于解決問題。
?
??? 例如,假設在 5 月 31 日晚上 10:00 開始運行表 REVENUE 上的統計信息收集作業,而隨后查詢的性能變差。Oracle 保存了原有的統計信息,您可以通過執行以下命令重新獲取這些信息:
?
begin
dbms_stats.restore_table_stats (
'ARUP',
'REVENUE',
'31-MAY-04 10.00.00.000000000 PM -04:00');
end;
?
??? 此命令恢復到 5 月 31 日晚上 10:00 為止的統計信息,時間信息是以 TIMESTAMP 數據類型提供。這樣您就立即還原了由新的統計信息收集程序所作的更改。
?
??? 您能夠恢復的時間長度是由保留參數所決定的。要查看當前的保留參數,可使用以下查詢:
?
SQL> select DBMS_STATS.GET_STATS_HISTORY_RETENTION from dual;
?
GET_STATS_HISTORY_RETENTION
---------------------------
???????????????????????? 31
?
??? 在本示例中表示可以保存相當于 31 天的統計信息,但并不能予以保證。要了解統計信息所覆蓋到的確切時間和日期,只需使用以下查詢:
?
SQL> select DBMS_STATS.GET_STATS_HISTORY_AVAILABILITY from dual;
?
GET_STATS_HISTORY_AVAILABILITY
---------------------------------------------------------------------
17-MAY-04 03.21.33.594053000 PM -04:00
?
??? 該查詢表明可用的最陳舊統計信息日期為 5 月 17 日凌晨 3:21。
?
??? 您可以通過執行內建的函數將保留時間設為不同的值。例如,要將其設為 45 天,可使用:
execute DBMS_STATS.ALTER_STATS_HISTORY_RETENTION (45)
?
?
有保證的還原保留功能
?
??? 自動還原保留功能是在 Oracle9i 中推出的,它極其有助于減少令人討厭的 ORA-1555 "Snapshot Too Old" 錯誤的出現機率。但是這些錯誤還是會出現,雖然其數量已大大減少。這是為什么呢?
?
??? 要回答這個問題,您需要了解還原段是如何工作的。當 Oracle 內部的數據發生變化時,高速緩存中的塊(在 SGA 中)立即發生變化,而過去的映像被存儲在還原段中。當事務提交時,不再需要舊的映像,因此可以重用它們。如果還原段中的所有空間都被活動的事務所使用,則 Oracle 將嘗試重用段中最陳舊的范圍(這一進程稱為“折返”,如 V$ROLLSTAT 視圖中的 WRAPS 列所示)。但是,在某些情況下,特別是在長時間運行的事務中,段將會擴展,為活動的事務提供空間,如 V$ROLLSTAT 中的列 EXTENDS 所示。如果查詢需要使用還原段范圍中的數據來創建數據的一致性視圖,但是該范圍已經被重用,則查詢產生 ORA-1555 錯誤。
?
??? 初始化參數 UNDO_RETENTION_PERIOD 指定必須保留多少還原數據(以秒為單位)。通過指定時間,Oracle 確保不重用陳舊的還原范圍,即使這些范圍處于不活動的狀態,或它們在還原保留時間內已經被更改,Oracle 也不會重用它們。這種方法減少了不活動范圍以后可能被查詢所意外重用的機率,這種重用會導致產生 ORA-1555 錯誤。
?
??? 但是,雖然 UNDO_RETENTION_PERIOD 指定了可以保留多少還原數據,它并不保證得到這種結果。當段不能擴展范圍時,最陳舊的不活動范圍被重用,以滿足當前事務的需要。因此,當查詢這些范圍時,某些與更改事務無關的長時運行的查詢可能會失敗,并產生 ORA-1555 錯誤。
?
??? 這個問題在 10g 中得到了解決:當您創建還原表空間時,您現在可以指定對還原保留功能的“保證”。下面是一個例子:
?
CREATE UNDO TABLESPACE UNDO_TS1
DATAFILE '/u01/oradata/proddb01/undo_ts1_01.dbf'
SIZE 1024M
RETENTION GUARANTEE;
?
??? 請注意最后的子句,它使還原表空間保證了對未過期還原范圍的保留。通過對現有還原表空間進行 ALTER 操作,也可以使其作出保證,如下所示:
?
ALTER TABLESPACE UNDO_TS2 RETENTION GUARANTEE;
?
??? 如果您不希望對保留作出保證(Oracle9i 中的行為)該怎么辦?那么,可執行以下操作:
?
ALTER TABLESPACE UNDO_TS2 RETENTION NOGUARANTEE;
?
??? 您可以使用以下語句來驗證表空間是否已經保證了還原保留功能:
?
SELECT RETENTION
FROM DBA_TABLESPACES
WHERE TABLESPACE_NAME = 'UNDO_TS1';
?
?
端到端跟蹤
?
??? 診斷性能問題的一種常見方法是啟用 sql_trace 來跟蹤數據庫調用,然后使用 tkprof 等工具來分析輸出。但是,這種方法在具有共享服務器體系結構的數據庫中具有嚴重的局限性。在這種配置中,創建了若干個共享服務器進程,為用戶的請求提供服務。當用戶 BILL 連接數據庫時,調度程序將連接傳遞到一個可用的共享服務器進程。如果沒有可用的共享服務器進程,則創建一個新進程。如果開始跟蹤該會話,則會跟蹤由共享服務器進程所進行的調用。
?
??? 現在假設 BILL 的會話變為空閑狀態,而 LORA 的會話變為活動狀態。此時最初為 BILL 提供服務的共享服務器被分配給 LORA 的會話。這樣,發出的跟蹤信息不是來自 BILL 的會話,而是來自 LORA 的會話。當 LORA 的會話變為非活動狀態時,該共享服務器可以被分配給另外的活動會話,這個會話將具有完全不同的信息。
?
??? 在 10g 中,通過使用端到端跟蹤,已經有效地解決了這一問題。在這種情況下,跟蹤不僅根據會話進行,還可根據客戶標識符等可識別的名稱來進行。一個名為 DBMS_MONITOR 的新程序包可用于此目的。
?
??? 例如,您可能希望跟蹤所有具有標識符 account_update 的會話。為建立跟蹤,您可以執行:
?
exec DBMS_MONITOR.CLIENT_ID_TRACE_ENABLE('account_update');
?
??? 此命令開始跟蹤所有具有標識符 account_update 的會話。當 BILL 連接數據庫時,他可以使用以下語句來設置客戶標識符:
?
exec DBMS_SESSION.SET_IDENTIFIER ('account_update')
?
??? 跟蹤對于具有標識符 account_update 的會話起作用,因此以上的會話將會被跟蹤,并會在用戶卸出目標目錄中產生一個跟蹤文件。如果另一個用戶連接數據庫并將其客戶標識符設置為 account_update,則自動跟蹤該會話,不需要在代碼中設置任何其他的命令。直到使用以下命令禁用跟蹤功能前,將跟蹤所有具有客戶標識符 account_update 的會話:
?
exec DBMS_MONITOR.CLIENT_ID_TRACE_ENABLE('account_update');
?
??? 作為結果的跟蹤文件可以由 tkprof 進行分析。但是,每個會話都產生不同的跟蹤文件。為了正確地診斷故障,我們關心合并的跟蹤文件而不是單獨的跟蹤文件。我們如何獲得合并的跟蹤文件呢?
?
??? 很簡單。利用一種稱為 trcsess 的工具,您可以將那些與客戶標識符 account_update 相關的信息提取到一個單獨的文件中,通過 tkprof 可以處理該文件。在以上的案例中,您可以轉到用戶卸出目標目錄中并運行:
?
trcsess output=account_update_trc.txt clientid=account_update *
?
??? 此命令創建一個名為 account_update_trc.txt 的文件,該文件與常規的跟蹤文件類似,但它只包含與那些具有客戶標識符 account_update 的會話相關的信息。該文件可以使用 tkprof 進行處理,以獲得經過分析的輸出。
?
??? 將這種方法和前一種更困難的跟蹤信息收集方法對比此外,跟蹤是由客戶標識符這樣的變量來啟用和禁止的,而不需要從該會話中調用 alter session set sql_trace = true。同一程序包中的另一個過程 SERV_MOD_ACT_TRACE_ENABLE 能夠在其他組合方式中啟用跟蹤功能,如用于特定服務、模塊或操作的組合,可以利用 dbms_application_info package 來進行設置。
?
?
數據庫的使用
?
??? 您的 Oracle 銷售代表將會確認,分區功能是要額外購買的選件,而在如今這個控制成本的時代,您可能希望了解用戶是否使用該選件 — 如果使用,使用的頻率怎樣。
?
??? 不必依賴于用戶的回答,只需查詢數據庫即可。自動工作負載信息庫(在第 6 周中有介紹)收集所有已安裝特性的使用情況信息,盡管每周只收集一次。
?
??? 兩個非常重要的視圖顯示了數據庫的使用模式。其中之一是 DBA_HIGH_WATER_MARK_STATISTICS,它顯示當前數據庫中使用的每個特性的最大值。以下是一個示例輸出。
?
NAME???????????? HIGHWATER LAST_VALUE DESCRIPTION
--------------- ---------- ---------- ----------------------------------------------------------
USER_TABLES??????????? 401??????? 401 Number of User Tables
SEGMENT_SIZE??? 1237319680 1237319680 Size of Largest Segment (Bytes)
PART_TABLES???????????? 12????????? 0 Maximum Number of Partitions belonging to an User Table
PART_INDEXES??????????? 12????????? 0 Maximum Number of Partitions belonging to an User Index
USER_INDEXES?????????? 832??????? 832 Number of User Indexes
SESSIONS??????????????? 19???????? 17 Maximum Number of Concurrent Sessions seen in the database
DB_SIZE???????? 7940079616 7940079616 Maximum Size of the Database (Bytes)
DATAFILES??????????????? 6????????? 6 Maximum Number of Datafiles
TABLESPACES????????????? 7????????? 7 Maximum Number of Tablespaces
CPU_COUNT??????????????? 4????????? 4 Maximum Number of CPUs
QUERY_LENGTH????????? 1176?????? 1176 Maximum Query Length
?
??? 可以看到,此視圖顯示了一些有關數據庫使用情況的有價值的信息 — 如用戶創建了一個最多可擁有 12 個分區的表,但現在卻沒有使用一個分區 (LAST_VALUE = 0)。這些信息在關閉狀態下也持續存在,這對于計劃操作非常有用,比如移植到不同的主機。
?
??? 但是,上述視圖仍然沒有回答我們所有的問題。它只是告訴我們曾經創建了具有 12 個分區的表,但沒有說明該特性的最后一次使用時間。另一個視圖 DBA_FEATURE_USAGE_STATISTICS 顯示了數據庫各種特性的使用情況,它可以回答這個問題。以下是該視圖分區特性的顯示情況,其中的列以縱向格式顯示。
?
DBID????????????????????????? : 4133493568
NAME????????????????????????? :Partitioning
VERSION?????????????????????? : 10.1.0.1.0
DETECTED_USAGES?????????????? : 12
TOTAL_SAMPLES???????????????? : 12
CURRENTLY_USED??????????????? :FALSE
FIRST_USAGE_DATE????????????? :16-oct-2003 13:27:10
LAST_USAGE_DATE?????????????? :16-dec-2003 21:20:58
AUX_COUNT???????????????????? :
FEATURE_INFO????????????????? :
LAST_SAMPLE_DATE????????????? :23-dec-2003 21:20:58
LAST_SAMPLE_PERIOD??????????? : 615836
SAMPLE_INTERVAL?????????????? : 604800
DESCRIPTION?????????????????? :Oracle Partitioning option is being used -
there is at least one partitioned object created.
?
??? 如本視圖所示,現在數據庫中沒有使用分區特性(列 CURRENTLY_USED 的值為 FALSE),最后一次使用該特性的時間是 2003 年 12 月 16 日晚上 9:20。使用信息的采樣時間為 604,800 秒或者說是 7 天,示于列 SAMPLE_INTERVAL 中。列 LAST_SAMPLE_DATE 顯示了對該使用信息的最后采樣時間,表明此信息的新舊程度。
?
??? 除了命令行接口之外,企業管理器 10g 還顯示以下信息。在 EM 中,在 Administration 標簽處單擊 Configuration Management 下方的“Database Usage Statistics”鏈接。(參見圖 1 和圖 2。)
?
圖 1:數據庫使用情況的統計信息頁面
?
圖 2:數據庫使用情況的統計信息;下鉆特性
?
?
更容易和更安全的加密
??? 還記得程序包 DBMS_OBFUSCATION_TOOLKIT (DOTK) 嗎?它是 Oracle9i 以及更低版本的數據庫中唯一可用的加密方法。盡管該程序包對于大部分數據庫而言已經足夠了,但是象大多數安全產品一樣,它很快就無法應付那些涉及高度敏感信息的高超的黑客攻擊。在所缺少的功能中,一個值得注意的功能是對高級加密標準 (AES) 的支持,該標準是以前的數字加密標準 (DES) 以及三倍 DES (DES3) 的一個功能更強的后繼標準。
?
??? 在 10g 中,一種更加完善的加密方法 DBMS_CRYPTO 用于處理這種問題。這個內建的程序包提供了 DOTK 中缺少的所有功能,并且對現有的函數和過程進行了增強。例如,DBMS_CRYPTO 可以使用新的 256 位 AES 算法進行加密。函數 ENCRYPT(也將其作為過程而超載)接受以下的幾個參數:
?