Oracle12c中SQL最佳化(SQL TUNING)新特性之SQL計劃指令
SQL計劃指令是Oracle12c中自適應查詢最佳化的功能之一。SQL計劃指令就像“額外的提醒” ,用以提醒最佳化器你先前選擇了的計劃並不是最優的,典型的是因為錯誤的勢評估。錯誤的勢評估往往是由統計資訊缺失,統計資訊陳舊,複雜的謂詞或操作等引起的。SQL計劃指令和SQL輪廓(SQL profiles)不同,後者是針對特定語句的,而SQL計劃指令和查詢表示式關聯,因此,它們可以被多個包含匹配查詢表示式的語句共享。柱狀圖或擴充套件統計資訊缺失也許會導致SQL計劃指令的產生。
資料庫在內部自動管理SQL計劃指令。像自動重最佳化的情況也許會引起SQL計劃指令被寫入SGA且稍後寫到SYSAUX表空間,此時,可以透過DBA_SQL_PLAN_DIRECTIVES和DBA_SQL_PLAN_DIR_OBJECTS檢視來檢視SQL計劃指令。此外,已存在的SQL計劃指令也能透過DBMS_SPD包來儲存。
1. 設定
確信共享池已經被清空,因此,我們知道在一個乾淨的系統上進行測試。
CONN sys@pdb1 AS SYSDBA
ALTER SYSTEM FLUSH SHARED_POOL;
下面的測試表包含指示省和市存在的列。這些列上有檢查約束,以便告訴最佳化器這些列被允許的值,此外,這些列上還有索引。透過包括10行A省和90行B省的樣本來模擬傾斜嚴重的資料。
CONN test/test@pdb1
DROP TABLE tab1 PURGE;
CREATE TABLE tab1 (
id NUMBER,
Province VARCHAR2(10),
city VARCHAR2(10),
CONSTRAINT tab1_pk PRIMARY KEY (id),
CONSTRAINT tab1_prov_chk CHECK (province IN ('A', 'B')),
CONSTRAINTtab1_city_chk CHECK (city IN ('X', 'Y'))
);
INSERT /*+ APPEND */ INTO tab1
SELECT level, 'A', 'X'
FROM dual
CONNECT BY level <= 10;
COMMIT;
INSERT /*+ APPEND */ INTO tab1
SELECT 10+level, 'B', 'Y'
FROM dual
CONNECT BY level <= 90;
COMMIT;
CREATE INDEX tab1_prov_idx ON tab1(province);
CREATE INDEX tab1_city_idx ON tab1(city);
EXEC DBMS_STATS.gather_table_stats(USER,'TAB1');
無論資料都沒傾斜,當用預設設定收集統計資訊時,不會為這些列建立柱狀圖。
COLUMN column_name FORMAT A20
SELECT column_id,
column_name,
histogram
FROM user_tab_columns
WHERE table_name = 'TAB1'
ORDER BY column_id;
COLUMN_ID COLUMN_NAME HISTOGRAM
---------- -----------------------------------
1 ID NONE
2 PROVINCE NONE
3 CITY NONE
SQL>
2. 顯示錯誤的勢評估
大家都知道,所有省和市都是關聯的。由於最佳化器並不知道這種關聯關係,並且也沒柱狀圖來標示資料的傾斜,接著最佳化器會利用現有資訊盡力為謂詞的選擇性做出評估。於是,它會假設資料均勻分佈在各允許值間且一半行被標為A省且一半被標為B省。如果在兩個列之間沒任何關聯,預期100/2/2=25行被標為即是A省和X市。下列查詢查出所有符合該規則的行,且顯示返回資料的執行計劃,包括預期的和實際的勢。
CONN test/test@pdb1
SELECT /*+ GATHER_PLAN_STATISTICS */
*
FROM tab1
WHERE province= 'A'
AND city= 'X';
SET LINESIZE 200 PAGESIZE 100
SELECT * FROMTABLE(DBMS_XPLAN.display_cursor(format => 'allstats last'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------
SQL_ID 5t8y8p5mpb99j, child number 0
-------------------------------------
SELECT /*+ GATHER_PLAN_STATISTICS */ *FROM tab1 WHERE province
= 'A' AND city = 'X'
Plan hash value: 1552452781
-----------------------------------------------------------------------------------------------------------------
| Id |Operation |Name | Starts | E-Rows |A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.01 | 4 |
|* 1| TABLE ACCESS BY INDEX ROWID BATCHED|TAB1 | 1 | 25 | 10 |00:00:00.01 | 4 |
|* 2| INDEX RANGE SCAN | TAB1_PROV_IDX | 1 | 50 | 10 |00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified byoperation id):
---------------------------------------------------
1 -filter("CITY"='X')
2 -access("PROVINCE"='A')
SQL>
正如預期的那樣,最佳化器得到了一個錯誤的勢評估。這是一個經典的案例,其中,柱狀圖,或擴充套件統計資訊,或兩者存在將有助於最佳化器能更精確的對勢做出評估。
下列查詢檢查V$SQL檢視的IS_REOPTIMIZABLE列,看最佳化器是否已注意到錯誤的勢評估。
CONN sys@pdb1 AS SYSDBA
COLUMN sql_text FORMAT A40
COLUMN is_reoptimizable FORMAT A16
SELECT sql_text, is_reoptimizable
FROM v$sql
WHERE sql_id = '5t8y8p5mpb99j';
SQL_TEXT IS_REOPTIMIZABLE
---------------------------------------- ----------------
SELECT /*+ GATHER_PLAN_STATISTICS */
*FROM tab1 WHERE province = 'A' AN
D city= 'X'
SQL>
由於該語句被標作可重新最佳化的,因此,SQL計劃指令也很可能已經被建立了。
3. 顯示SQL計劃指令
至此,最佳化器已經把SQL計劃指令寫入了SGA,但是我們還不能看到它們,因為它們還沒被寫入SYSAUX表空間。
CONN sys@pdb1 AS SYSDBA
SET LINESIZE 200
COLUMN dir_id FORMAT A20
COLUMN owner FORMAT A10
COLUMN object_name FORMAT A10
COLUMN col_name FORMAT A10
SELECT TO_CHAR(d.directive_id) dir_id,o.owner, o.object_name,
o.subobject_name col_name, o.object_type, d.type, d.state, d.reason
FROM dba_sql_plan_directives d, dba_sql_plan_dir_objects o
WHERE d.directive_id=o.directive_id
AND o.owner = 'TEST'
ORDER BY 1,2,3,4,5;
no rows selected
SQL>
我們可以等資料庫把SQL計劃指令儲存,或用DBMS_SPD包手工儲存。
CONN sys@pdb1 AS SYSDBA
EXEC DBMS_SPD.flush_sql_plan_directive;
現在我們執行前面的查詢,將會看到SQL計劃指令。
CONN sys@pdb1 AS SYSDBA
SET LINESIZE 200
COLUMN dir_id FORMAT A20
COLUMN owner FORMAT A10
COLUMN object_name FORMAT A10
COLUMN col_name FORMAT A10
SELECT TO_CHAR(d.directive_id) dir_id,o.owner, o.object_name,
o.subobject_name col_name, o.object_type, d.type, d.state, d.reason
FROM dba_sql_plan_directives d, dba_sql_plan_dir_objects o
WHERE d.directive_id=o.directive_id
AND o.owner = 'TEST'
ORDER BY 1,2,3,4,5;
DIR_ID OWNER OBJECT_NAM COL_NAME OBJECTTYPE STATE REASON
-------------------- ---------- -------------------- ------ ---------------- ----------------------------------------------
12422623998396966202 TEST TAB1 PROVINCE COLUMN DYNAMIC_SAMPLING USABLE SINGLE TABLE CARDINALITY MISESTIMATE
12422623998396966202 TEST TAB1 TABLE DYNAMIC_SAMPLING USABLE SINGLE TABLE CARDINALITY MISESTIMATE
SQL>
4. 顯示SQL計劃指令的使用
下列查詢是剛才我們產生SQL計劃指令的那個。注意,勢評估發生了改變,且在DBMS_XPLAN輸出末尾出現了提醒。
CONN test/test@pdb1
SELECT /*+ GATHER_PLAN_STATISTICS */
*
FROM tab1
WHERE province= 'A'
AND city= 'X';
SET LINESIZE 200 PAGESIZE 100
SELECT * FROMTABLE(DBMS_XPLAN.display_cursor(format => 'allstats last'));
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------
SQL_ID 5t8y8p5mpb99j, child number 1
-------------------------------------
SELECT /*+ GATHER_PLAN_STATISTICS */ *FROM tab1 WHERE province
= 'A' AND city = 'X'
Plan hash value: 1552452781
-----------------------------------------------------------------------------------------------------------------
| Id |Operation |Name | Starts | E-Rows |A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------
| 0 |SELECT STATEMENT | | 1 | | 10 |00:00:00.01 | 4 |
|* 1| TABLE ACCESS BY INDEX ROWID BATCHED|TAB1 | 1 | 10 | 10 |00:00:00.01 | 4 |
|* 2| INDEX RANGE SCAN | TAB1_PROV_IDX | 1 | 10 | 10 |00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified byoperation id):
---------------------------------------------------
1 -filter("CITY"='X')
2 -access("PROVINCE"='A')
Note
-----
-dynamic statistics used: dynamic sampling (level=2)
-statistics feedback used for this statement
- 1Sql Plan Directive used for this statement
SQL>
5. SQL 計劃指令和統計資訊
SQL計劃指令典型是一個“丟失資訊” 的指示,但這些“丟失的資訊”也許將來會變大的可用。如果我們重新收集表TAB1的統計資訊,我們會注意到存在傾斜資料的列已被收集了統計資訊。
EXEC DBMS_STATS.gather_table_stats(USER,'TAB1');
SELECT column_id,
column_name,
histogram
FROM user_tab_columns
WHERE table_name = 'TAB1'
ORDER BY column_id;
COLUMN_ID COLUMN_NAME HISTOGRAM
---------- -----------------------------------
1 ID NONE
2 PROVINCE FREQUENCY
3 CITY FREQUENCY
SQL>
如果收集了擴充套件統計資訊,可用下面的語句檢視它們。
COLUMN extension FORMAT A30
SELECT extension_name, extension
FROM user_stat_extensions;
一旦需要的柱狀圖或擴充套件資訊存在,或如果替代SQL計劃指令被建立,則該SQL計劃指令也許就會切換到一個替代狀態而不再被使用。
CONN sys@pdb1 AS SYDBA
SELECT state, COUNT(*)
FROM dba_sql_plan_directives
GROUP BY state
ORDER BY state;
STATE COUNT(*)
---------- ----------
SUPERSEDED 26
USABLE 44
SQL>
預設的,SQL計劃指令超過53周不被使用就會被刪除。而某些SQL計劃指令會對列組統計資訊的收集有影響。
6. DBMS_SPD包
DBMS_SPD包可以在一定程度上控制SQL計劃指令。
可以用以下過程來進行基本的SQL計劃指令管理。
1) FLUSH_SQL_PLAN_DIRECTIVE:將SGA中的SQL計劃指令存入SYSAUX表空間。
2) ALTER_SQL_PLAN_DIRECTIVE:更改確定SQL計劃指令的ENABLED和AUTO_DROP屬性。
3) DROP_SQL_PLAN_DIRECTIVE:刪除確定的SQL計劃指令。
SQL計劃指令不使用而被保留的最長時間透過 SPD_RETENTION_WEEKS確定,預設為53周。這可以用如下過程顯示和修改。
1) GET_PREFS :顯示確定的偏好(preference)。目前只支援SPD_RETENTION_WEEKS。
2) SET_PREFS :設定確定的偏好(preference)。目前只支援SPD_RETENTION_WEEKS。
SQL計劃執行的長期儲存和遷移可以用如下過程。
1) CREATE_STGTAB_DIRECTIVE:建立一個將SQL計劃指令匯出到的中間表。
2) PACK_STGTAB_DIRECTIVE:將SQL計劃指令匯出到指定表。
3) UNPACK_STGTAB_DIRECTIVE:從中間表匯入SQL計劃指令。
DBMS_SPD包的很多功能需要ADMINISTER SQL MANAGEMENTOBJECT許可權。
7. 註釋:
有時SQL計劃指令內部管理機制看起來有些混亂。測試期間,我遇到過本來希望它被建立但卻沒有。也遇到過本希望存在的SQL計劃指令標作被替代狀態但卻沒有。開始我認為這可能是因為我忘了儲存,但情況似乎並非如此。
記得查詢 DBA_SQL_PLAN_DIRECTIVES和DBA_SQL_PLAN_DIR_OBJECTS檢視前總是執行DBMS_SPD.FLUSH_SQL_PLAN_DIRECTIVE過程。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8484829/viewspace-2120968/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- oracle11g中SQL最佳化(SQL TUNING)新特性之SQL Plan Management(SPM)OracleSQL
- Oracle12c中SQL最佳化新特性之自動重最佳化(automatic reoptimization)OracleSQL
- Oracle12c中PL/SQL(DBMS_SQL)新特性之隱式語句結果OracleSQL
- Oracle SQL最佳化之sql tuning advisor(STA)OracleSQL
- 23c 新特性之實時SQL計劃管理SQL
- Oracle中SQL調優(SQL TUNING)之最權威獲取SQL執行計劃大全OracleSQL
- Oracle 11g 中SQL效能最佳化新特性之SQL效能分析器(SQLPA)OracleSQL
- 使用sql tuning advisor最佳化sqlSQL
- 使用SQL Profile及SQL Tuning Advisor固定執行計劃SQL
- oracle SQL最佳化器SQL Tuning Advisor (STA)OracleSQL
- sql tuning之變通SQL
- oracle12c新特性(7)--如何在RMAN中執行SQL語句OracleSQL
- Oracle SQL優化之sql tuning advisorOracleSQL優化
- sql tuningSQL
- sql tuning task和sql profileSQL
- Automatic SQL Tuning and SQL ProfilesSQL
- Oracle SQL優化之sql tuning advisor(STA)OracleSQL優化
- SQL最佳化案例-從執行計劃定位SQL問題(三)SQL
- oracle11g中SQL最佳化新特性之Adaptive Cursor Sharing (ACS)OracleSQLAPT
- sql tuning set/sql tuning advisor(待完善)SQL
- 23c 新特性之SQL_transpilerSQL
- 23C新特性SQL防火牆 (SQL Firewall)SQL防火牆
- sql tuning setSQL
- 熟悉SQL tuningSQL
- SQL最佳化 —— 讀懂執行計劃SQL
- sql最佳化:使用儲存提綱穩定sql執行計劃SQL
- 透過分析SQL語句的執行計劃最佳化SQL(總結)SQL
- 【筆記】SQL tuning筆記SQL
- Oracle SQL Perfomance TuningOracleSQL
- 掌握SQL Monitor這些特性,SQL最佳化將如有神助!SQL
- Sql最佳化(二十二) 自動調優工具:sql tuning advisor和sql profile介紹SQL
- SQL最佳化 之 -- joinSQL
- SPA_SQL Performance Analyzer_SQL Tuning SetSQLORM
- sql最佳化:使用sql profile最佳化sql語句SQL
- [轉]透過分析SQL語句的執行計劃最佳化SQL(總結)SQL
- sql 執行計劃SQL
- 控制執行計劃之-SQL Profile(一)SQL
- Mysql SQL最佳化系列之——執行計劃連線方式淺釋MySql