在上一期中說到了SQL Tuning Advisor其中一個影響對象就是SQL Profile,同樣在管理和應用開發中,SQL性能優化是個任重道遠的工作,低效的SQL語句讓應用響應緩慢,用戶整體體驗下降,拖垮搞蹦整個系統都有可能。Oracle數據庫提供了多種組合工具,有的免費有的是需要許可,系統而全面地解決這些性能問題。SQL自動調優(Automatic SQL Tuning)與SQL Profile是從10g就引入的重要特性,提供解決SQL性能問題強大的支持。
一、SQL是否需要自動調優,什么情況下可以接受自動?
- 但是在一些因素的影響下,CBO會受影響出次優或是更差的選擇,例如:
- 統計信息過時或缺失:當表的數據量、數據分布發生顯著變化,而統計信息未能及時更新時,優化器基于舊信息做出的判斷可能不再準確。
- 復雜的查詢結構:對于包含多表連接、子查詢、復雜謂詞的SQL,優化器估算成本的難度會大大增加。(23ai之后有了機器學習是不是有提升)
- 原生優化器局限性:優化器模型本身可能無法完美處理所有情況。
- 傳統的解決方法通常是在SQL語句中手動添加提示(Hints),以指導優化器選擇特定的場景,但這種方式又降存在這些缺陷:
- 侵入式修改:需要修改應用程序代碼,對于已封裝的商業軟件或第三方系統,幾乎是不可能的任務,且不可延續。
- 維護困難:隨著數據和業務需求需求調整和運行環境的變化,也許當前有效的Hint,就在不遠的下一次失效甚至產生負面影響。
二、SQL Profile 分類與原理?
?1. Auto SQL Profile(基于SQL Tuning Advisor)??
- ?分析階段?:校驗統計信息、識別異常訪問路徑(如缺失索引或全表掃描成本失真)。
- ?生成階段?:自動創建校正因子(如將表基數從100修正為100萬)。
- ?生效機制?:優先使用Profile中的統計信息覆蓋默認值,優化器據此重新計算成本。
- ?自動化高效?:一鍵生成,適合批量優化AWR中的高頻低效SQL。
- ?動態適應?:隨數據變化自動調整,避免計劃固化(如新增索引時自動啟用)。
- ?低風險?:內置成本對比驗證,規避極端路徑(如不會強制禁用所有索引)。
- ?優化局限?:無法突破優化器規則(如不能強制嵌套循環替代哈希連接)。
- ?環境依賴?:嚴重依賴當前統計信息,跨環境遷移(測試→生產)可能失效。
- ?黑盒操作?:修正邏輯存儲在隱藏表 SQLPROF$,問題追溯困難。
2. 手工SQL Profile?
- 提取原始SQL的Outline Data。
- 通過Hint改寫SQL生成目標Outline Data。
- 將腳改寫的帶有Hint的替換原始的版本,生成最終Profile。
- ?精準控制?:繞過優化器決策,強制固定最優路徑(如索引掃描、連接順序)。
- ?優先級碾壓?:覆蓋SQL中的硬編碼Hint(如 /*+ FULL(T) */ 無效)。
- ?靈活生效?:通過?CATEGORY 按會話/環境隔離(如測試環境用 DEV 類別、生產用PROD)。
- ?技術門檻高?:需深入理解成本模型,錯誤設置引發性能惡化(如基數誤判導致笛卡爾積)。
- ?維護成本大?:表結構變更(如索引刪除)需人工重新驗證Profile有效性。
- ?過優化風險?:強制計劃可能失效(如索引失效仍強制掃描,引發全表掃描被禁用)。
三. 實操演示:23 ai上HR.T4SQLPROFILE 表實驗?
?步驟1:創建測試環境?
SYS@CDB$ROOT> alter session set container=FREEPDB1;
-- 建表并模擬插入不均衡數據
CREATE TABLE HR.T4SQLPROFILE AS
SELECT * FROM DBA_OBJECTS WHERE ROWNUM <= 10000;INSERT INTO HR.T4SQLPROFILE
SELECT * FROM DBA_OBJECTS
WHERE object_id = 100 AND ROWNUM <= 9000; -- 90% 數據集中CREATE INDEX HR.IDX_T4SQLPROFILE ON HR.T4SQLPROFILE(object_id);-- 收集統計信息
BEGINDBMS_STATS.GATHER_TABLE_STATS('HR','T4SQLPROFILE');
END;
/
--PL/SQL procedure successfully completed.
步驟2:自動 Profile 實驗
官方文檔DBMS_SQLTUNE.ACCEPT_SQL_PROFILE 的 FORCE_MATCH 參數默認值為 FALSE,即必須在 SQL 文本完全匹配時應用 SQL Profile才會被使用,若目標 SQL 文本有改動即使是where 后面的字句查詢不一致,原有 SQL Profile 就失效。。所以必須設置“DBMS_SQLTUNE.ACCEPT_SQL_PROFILE(task_name, force_match=>TRUE);”
-- 低效全表掃描(因 NO_INDEX Hint)
SELECT /*+ NO_INDEX(T) */ * FROM HR.T4SQLPROFILE T WHERE object_id=10;-- 創建調優任務并接受 Profile
DECLAREtask_name VARCHAR2(50);
BEGINtask_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_text => 'SELECT /*+ NO_INDEX(T) */ * FROM HR.T4SQLPROFILE T WHERE object_id=10',scope => 'COMPREHENSIVE',task_name => 'AUTO_TUNE_TASK');DBMS_SQLTUNE.EXECUTE_TUNING_TASK(task_name);DBMS_SQLTUNE.ACCEPT_SQL_PROFILE(task_name, force_match=>TRUE);
END;
/-- 驗證:計劃轉為索引掃描
--驗證SQL Profile被接受,同時查詢走index
SELECT * FROM HR.T4SQLPROFILE WHERE object_id=10;
--
SYS@CDB$ROOT> SELECT * FROM HR.T4SQLPROFILE WHERE object_id=10;
SYS C_USER# 10 10 CLUSTER 24-APR-25
--
SYS@CDB$ROOT> SET AUTOTRACE ON
Autotrace TraceOnlyExhibits the performance statistics with silent query output
SELECT * FROM HR.T4SQLPROFILE WHERE object_id=20;
SYS@CDB$ROOT> SELECT * FROM HR.T4SQLPROFILE WHERE object_id=20;1 row selected.SQL_ID cy30yj4480y2q, child number 0
-------------------------------------
SELECT * FROM HR.T4SQLPROFILE WHERE object_id=20Plan hash value: 2117281514-------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| T4SQLPROFILE | 1 |
|* 2 | INDEX RANGE SCAN | IDX_T4SQLPROFILE | 1 |
-------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - access("OBJECT_ID"=20)Note
------ Warning: basic plan statistics not available. These are only collected when:* hint 'gather_plan_statistics' is used for the statement or* parameter 'statistics_level' is set to 'ALL', at session or system levelStatistics
-----------------------------------------------------------1 CPU used by this session1 CPU used when call started5 Requests to/from client4 SQL*Net roundtrips to/from client4 buffer is not pinned count944 bytes received via SQL*Net from client67782 bytes sent via SQL*Net to client5 calls to get snapshot scn: kcmgss2 calls to kcmgcs4 consistent gets1 consistent gets examination1 consistent gets examination (fastpath)4 consistent gets from cache3 consistent gets pin3 consistent gets pin (fastpath)1 enqueue releases1 enqueue requests2 execute count1 index range scans32768 logical read bytes from cache3 no work - consistent read gets10 non-idle wait count2 opened cursors cumulative1 opened cursors current1 parse count (hard)2 parse count (total)169 process last non-idle time1 recursive calls4 session logical reads1 sorts (memory)1620 sorts (rows)1 table fetch by rowid5 user calls
SYS@CDB$ROOT>
四、 SQL Profile 管理指南?
?常用操作
?操作? | 命令/視圖 |
?查看 Profile? | SELECT name, category, status FROM dba_sql_profiles; |
?禁用/啟用 | DBMS_SQLTUNE.ALTER_SQL_PROFILE(name=>'PROF1', attribute_name=>'STATUS', value=>'DISABLED'); |
?刪除 Profile | DBMS_SQLTUNE.DROP_SQL_PROFILE('PROF1'); |
?遷移 Profile? | 使用DBMS_SQLTUNE.PACK_STGTAB_SQLPROF導出導入 |
關鍵管理場景?
- ?環境隔離?:通過 CATEGORY 控制 Profile 生效范圍(如測試環境用 DEV ,生產用PROD)。
- ?版本升級?:使用數據泵導出 SQLPROF$ 表實現跨版本遷移。
- ?性能監控?:結合 AWR 報告檢查 SQL Profile 的使用效果。
?管理SQL Profile
-- 查看所有 Profile
SELECT name, category, status, sql_text
FROM dba_sql_profiles;
--
SYS@CDB$ROOT> SELECT name, category, status, sql_text FROM dba_sql_profiles;
SYS_SQLPROF_0197914a1f230000 DEFAULT ENABLED SELECT /*+ NO_INDEX(T) */ * FROM HR.T4SQLPROFILE T WHERE object_id=10-- 禁用/啟用 Profile
BEGINDBMS_SQLTUNE.ALTER_SQL_PROFILE(name => 'SYS_SQLPROF_0197914a1f230000',attribute_name => 'STATUS',value => 'DISABLED' -- 或 'ENABLED');
END;
/-- 刪除 Profile
EXEC DBMS_SQLTUNE.DROP_SQL_PROFILE('SYS_SQLPROF_0197914a1f230000');
五、使用體驗?
- ?自動 Profile? 適合解決統計信息不準導致的偶發性性能問題,動態適應數據變化。
- ?手動 Profile? 用于鎖定最優計劃,尤其適合關鍵業務 SQL 或第三方系統不可改源碼的場景。
- ?最佳實踐?:
- 優先嘗試自動 Profile
- 對核心事務 SQL 使用手動 Profile 強控計劃
- 通過 force_match 和 category 提升靈活性和安全性