新聞中心
需要綁定SQL執(zhí)行計(jì)劃常見的幾種情況:
SQL執(zhí)行計(jì)劃突變,導(dǎo)致數(shù)據(jù)庫(kù)性能下降,從歷史執(zhí)行計(jì)劃找一個(gè)合理的,進(jìn)行綁定。
SQL無(wú)法使用更優(yōu)的執(zhí)行計(jì)劃,且無(wú)歷史執(zhí)行計(jì)劃,可通過hint手工構(gòu)造的方式,進(jìn)行綁定。
某些Bug引起優(yōu)化器生成較差的執(zhí)行計(jì)劃。在bug修復(fù)前,進(jìn)行綁定。
ORACLE固定執(zhí)行計(jì)劃的3種方式:
Oracle 9i使用outline (可跨版本10,11g均可使用)
Oracle 10g使用sql profile (11g也可使用)
Oracle 11g使用sql plan manage
接下來(lái)簡(jiǎn)述如何使用這3種方式進(jìn)行執(zhí)行計(jì)劃的固定,并舉例說(shuō)明3種固定執(zhí)行計(jì)劃的優(yōu)缺點(diǎn),通過對(duì)比選擇合適的固定執(zhí)行計(jì)劃來(lái)應(yīng)對(duì)不同的業(yè)務(wù)場(chǎng)景。也就是什么場(chǎng)景下使用何種執(zhí)行計(jì)劃固定比較合適。
一、大綱(Stored Outline)
語(yǔ)法:(手動(dòng)創(chuàng)建outline)
CREATE [ OR REPLACE ]
[ PUBLIC | PRIVATE ] OUTLINE [ outline ]
[ FROM [ PUBLIC | PRIVATE ] source_outline ]
[ FOR CATEGORY category ]
[ ON statement ] ;
1、當(dāng)SQL執(zhí)行計(jì)劃因新版本變更,統(tǒng)計(jì)信息不準(zhǔn)確,新建索引,參數(shù)改變等發(fā)生改變時(shí),存儲(chǔ)大綱可以使SQL語(yǔ)句的執(zhí)行計(jì)劃保持不變。在創(chuàng)建某條語(yǔ)句的大綱時(shí),ORACLE會(huì)將SQL語(yǔ)句的文本,執(zhí)行計(jì)劃和語(yǔ)句使用的hints存儲(chǔ)在一個(gè)系統(tǒng)默認(rèn)用戶OUTLN的3個(gè)表OL$,OL$HINTS,OL$NODES上。
2、使用大綱(outline)固定執(zhí)行計(jì)劃
--環(huán)境構(gòu)建,建立測(cè)試表
SQL> create table zw as select * from dba_objects where object_id is not null;
Table created.
SQL> explain plan for select count(*) from zw;
Explained.
SQL> set lines 200
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------
Plan hash value: 249608387
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 339 (1)| 00:00:05 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| ZW | 100K| 339 (1)| 00:00:05 |
-------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
13 rows selected.
--查詢數(shù)據(jù)字典dba_outlines:
SQL> select NAME,OWNER,CATEGORY,USED,SQL_TEXT,ENABLED,TIMESTAMP from dba_outlines;
no rows selected
--創(chuàng)建大綱(全表掃描),默認(rèn)是私有outline
SQL> create or replace outlinezwoutlinefor category mycate onselect count(*) from zw;
Outline created.
--再次查詢dba_outlines;
col NAME for a10
col OWNER for a10
col CATEGORY for a10
col SQL_TEXT for a30
select NAME,OWNER,CATEGORY,USED,SQL_TEXT,ENABLED,TIMESTAMP from dba_outlines;
NAME OWNER CATEGORY USED SQL_TEXT ENABLED TIMESTAMP
---------- ---------- ---------- ------ ------------------------------ -------- -------------------
ZWOUTLINE SYS MYCATE UNUSEDselect count(*) from zw ENABLED 2017-09-02 15:36:33
--創(chuàng)建object_id列索引,將該列屬性設(shè)置為非空
--索引不存儲(chǔ)null值
SQL> alter table zw modify object_id not null;
Table altered.
SQL> create index idx_zw_obj_id on zw(object_id);
Index created.
SQL> analyze table zw compute statistics;
Table analyzed.
SQL> explain plan for select count(*) from zw;
Explained.
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1836624960
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 54 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_ZW_OBJ_ID | 100K| 54 (0)| 00:00:01 |
-------------------------------------------------------------------------------
--使用大綱固定執(zhí)行計(jì)劃:(alter system/session set use_stored_outlines=mycate;)系統(tǒng)級(jí)或會(huì)話級(jí)別;
SQL> alter systemset use_stored_outlines=mycate;
System altered.
--查詢dba_ouitlines(sql還未應(yīng)用)
SQL> select NAME,OWNER,CATEGORY,USED,SQL_TEXT,ENABLED,TIMESTAMP from dba_outlines;
NAME OWNER CATEGORY USED SQL_TEXT ENABLED TIMESTAMP
---------- ---------- ---------- ------ ------------------------------ -------- -------------------
ZWOUTLINE SYS MYCATE UNUSED select count(*) from zw ENABLED 2017-09-02 15:36:33
--固定執(zhí)行計(jì)劃之后,就會(huì)按照創(chuàng)大綱時(shí)的執(zhí)行計(jì)劃去執(zhí)行。
實(shí)際執(zhí)行驗(yàn)證:(實(shí)際執(zhí)行后就會(huì)應(yīng)用outline)
SQL> select count(*) from zw;
COUNT(*)
----------
87036
SQL> select * from table(dbms_xplan.display_cursor(null, null, 'advanced'));
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------
SQL_ID 1f5n0rapts695, child number 0
-------------------------------------
select count(*) from zw
Plan hash value: 1836624960
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 54 (100)| |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_ZW_OBJ_ID | 87036 | 54 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1 / ZW@SEL$1
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
DB_VERSION('11.2.0.4')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
INDEX_FFS(@"SEL$1" "ZW"@"SEL$1" ("ZW"."OBJECT_ID"))
END_OUTLINE_DATA
*/
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - (#keys=0) COUNT(*)[22]
39 rows selected.
--查詢dba_outlines
select NAME,OWNER,CATEGORY,USED,SQL_TEXT,ENABLED,TIMESTAMP from dba_outlines;
NAME OWNER CATEGORY USED SQL_TEXT ENABLED TIMESTAMP
---------- ---------- ---------- ------ ------------------------------ -------- -------------------
ZWOUTLINE SYS MYCATE UNUSED select count(*) from zw ENABLED 2017-09-02 15:54:31
上述的建立的大綱為公有大綱,為了不影響其它用戶的使用,可以建立私有大綱如下:
create or replace private outline zwoutline2 for category mycate2 on select count(*) from zw;
思考:為什么我構(gòu)建測(cè)試時(shí),固定的是全表掃描,而不是比較優(yōu)化的索引掃描?
其實(shí)這里我想說(shuō)明的是outline的缺點(diǎn)是比較死板的,當(dāng)創(chuàng)建新的索引,或者數(shù)據(jù)量大幅度變化時(shí)是無(wú)法做出相應(yīng)改變的,也就是說(shuō)它是固定死的。
關(guān)于outline具體參考如下鏈接:
http://blog.csdn.net/whiteoldbig/article/details/17210079
- 這種方法不能指定outline的具體名字,由系統(tǒng)自動(dòng)生成,可以通過alter outline SYS_OUTLINE_14061114223605901 rename to dh_test2修改
- 不指定類別的話默認(rèn)為default,而且此處創(chuàng)建時(shí),不能指定為default類別(會(huì)報(bào)錯(cuò))。
- 我們使用outline固定執(zhí)行計(jì)劃時(shí),一般都是選用此種方法
參考:
http://www.bubuko.com/infodetail-216529.html
實(shí)驗(yàn)如下:
SQL> create table dh_stat as select rownum id ,object_name name ,object_type type from dba_objects;
Table created.
SQL> create index ind_1 on dh_stat(id) compute statistics;
Index created.
SQL> alter system flush shared_pool;
System altered.
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>'sys',TABNAME=>'dh_stat',ESTIMATE_PERCENT=>30,METHOD_OPT=>'FOR ALL COLUMNS SIZE 1',NO_INVALIDATE=>FALSE,CASCADE=>TRUE,DEGREE => 1);
PL/SQL procedure successfully completed.
SQL> col name format a15
SQL> col name format a30
SQL> col sql_text for a55
SQL> select /* outlinetest1 */ * from dh_stat where id=771;
ID NAME TYPE
---------- ------------------------------ -------------------
771 SYS_IL0000000772C00002$$ INDEX
SQL> set lines 200
SQL> select sql_text,sql_id,hash_value,child_number from v$sql a where sql_text like '%outlinetest1%' and sql_text not like '%v$sql%';
SQL_TEXT SQL_ID HASH_VALUE CHILD_NUMBER
------------------------------------------------------- ------------- ---------- ------------
select /* outlinetest1 */ * from dh_stat where id=771 9a69w18a8uuhk 344812050 0
SQL> select * from table(dbms_xplan.display_cursor('9a69w18a8uuhk',null));
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
SQL_ID 9a69w18a8uuhk, child number 0
-------------------------------------
select /* outlinetest1 */ * from dh_stat where id=771
Plan hash value: 2780970545
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| DH_STAT | 1 | 39 | 2 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------
|* 2 | INDEX RANGE SCAN | IND_1 | 1 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=771)
19 rows selected.
---根據(jù)sql已經(jīng)有的執(zhí)行計(jì)劃生成outline:
SQL> exec DBMS_OUTLN.create_outline(hash_value=>344812050,child_number => 0,category=>'TEST');
PL/SQL procedure successfully completed.
--查詢outline情況:
SQL> select name,category,used,sql_text from dba_outlines;
NAME CATEGORY USED SQL_TEXT
------------------------------ ------------------------------ ------ -------------------------------------------------------
SYS_OUTLINE_17090216454529101 TEST UNUSED select /* outlinetest1 */ * from dh_stat where id=771
此處outline的USED狀態(tài)沒有改變,因?yàn)槲覀儧]有激活TEST類別的outline,再次申明,outline必須通過use_stored_outlines參數(shù)激活后,優(yōu)化器才會(huì)使用outline
---下面這一步激活TEST類別的OUTLINE,也可以在系統(tǒng)級(jí)激活OUTLINE
SQL> alter session set use_stored_outlines=TEST;
驗(yàn)證省略。。。。。。。。。。。

創(chuàng)新互聯(lián)專注于中大型企業(yè)的網(wǎng)站設(shè)計(jì)制作、網(wǎng)站設(shè)計(jì)和網(wǎng)站改版、網(wǎng)站營(yíng)銷服務(wù),追求商業(yè)策劃與數(shù)據(jù)分析、創(chuàng)意藝術(shù)與技術(shù)開發(fā)的融合,累計(jì)客戶上千,服務(wù)滿意度達(dá)97%。幫助廣大客戶順利對(duì)接上互聯(lián)網(wǎng)浪潮,準(zhǔn)確優(yōu)選出符合自己需要的互聯(lián)網(wǎng)運(yùn)用,我們將一直專注高端網(wǎng)站設(shè)計(jì)和互聯(lián)網(wǎng)程序開發(fā),在前進(jìn)的路上,與客戶一起成長(zhǎng)!
二、SQL_PROFILE
1、DBMS_SQLTUNE是10g引入的一個(gè)新特性,它可以通過自動(dòng)優(yōu)化性能較差SQL,并給出合理的優(yōu)化建議,其中優(yōu)化建議中的sql_profile文件它是一個(gè)存儲(chǔ)在數(shù)據(jù)字典中的信息集合。sql_profile不包含單獨(dú)的執(zhí)行計(jì)劃,提供數(shù)據(jù)庫(kù)配置、綁定變量、優(yōu)化統(tǒng)計(jì)信息、數(shù)據(jù)集等信息供優(yōu)化器選擇執(zhí)行計(jì)劃。這里不對(duì)SQL優(yōu)化建議工具SQL Tuning Advisor STA)進(jìn)行介紹,有興趣的童鞋研究一下DBMS_SQLTUNE包。
語(yǔ)法:
SQL text format:
DBMS_SQLTUNE.CREATE_TUNING_TASK( sql_text IN CLOB, bind_list IN sql_binds := NULL, user_name IN VARCHAR2 := NULL, scope IN VARCHAR2 := SCOPE_COMPREHENSIVE, time_limit IN NUMBER := TIME_LIMIT_DEFAULT, task_name IN VARCHAR2 := NULL, description IN VARCHAR2 := NULL) RETURN VARCHAR2;
SQL ID format:
DBMS_SQLTUNE.CREATE_TUNING_TASK( sql_id IN VARCHAR2, plan_hash_value IN NUMBER := NULL, scope IN VARCHAR2 := SCOPE_COMPREHENSIVE, time_limit IN NUMBER := TIME_LIMIT_DEFAULT, task_name IN VARCHAR2 := NULL, description IN VARCHAR2 := NULL) RETURN VARCHAR2;
Workload Repository format:
DBMS_SQLTUNE.CREATE_TUNING_TASK(
begin_snap IN NUMBER,
end_snap IN NUMBER,
sql_id IN VARCHAR2,
plan_hash_value IN NUMBER := NULL,
scope IN VARCHAR2 := SCOPE_COMPREHENSIVE,
time_limit IN NUMBER := TIME_LIMIT_DEFAULT,
task_name IN VARCHAR2 := NULL,
description IN VARCHAR2 := NULL)
RETURN VARCHAR2;
實(shí)驗(yàn)1:sql_id format
1. sys用戶創(chuàng)建oracle優(yōu)化任務(wù)(v_sqlid,task_name根據(jù)實(shí)際情況改變)
set long 10000000 longchunksize 1000000 linesize 150 pagesize 0 serveroutput on size 1000000 verify off
declare
my_task_name varchar2(30);
v_sqlid varchar2(50);
begin
v_sqlid:='11wrxmug9y4a7';
my_task_name := dbms_sqltune.create_tuning_task
(sql_id=> v_sqlid,
scope => 'comprehensive',
time_limit=>160,
task_name=>'task_00000',
description => 'tuning task');
dbms_sqltune.execute_tuning_task('task_00000');
end;
/
注:dbms_sqltune.execute_tuning_task('task_00000'),是執(zhí)行優(yōu)化任務(wù)
2. 打印優(yōu)化任務(wù),里面有一些具體的改進(jìn)措施
select dbms_sqltune.report_tuning_task('task_00000') from dual;
3.根據(jù)優(yōu)化建議,綁定profile,理論上可提高語(yǔ)句執(zhí)行效率
execute dbms_sqltune.accept_sql_profile(task_name => 'task_00000',task_owner => 'sys', replace => true);
實(shí)驗(yàn)2:sql_text format
SQL> alter session set statistics_level=all;
Session altered.
SQL> set serveroutput off
SQL> select * from scott.emp where ename='SCOTT' and DEPTNO=20;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
SQL> SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'runstats_last'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID 4dsqbp572auuu, child number 0
-------------------------------------
select * from scott.emp where ename='SCOTT' and DEPTNO=20
Plan hash value: 3956160932
------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 7 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 1 | 1 |00:00:00.01 | 7 |
PLAN_TABLE_OUTPUT
---------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("ENAME"='SCOTT' AND "DEPTNO"=20))
18 rows selected.
SQL> DECLARE
my_task_name VARCHAR2(30);
my_sqltext CLOB;
BEGIN
my_sqltext := 'select * from scott.emp where ename= :name and DEPTNO= :deptno';
my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(
sql_text => my_sqltext,
bind_list => sql_binds(anydata.convertvarchar2(10),anydata.convertnumber(2)),
user_name => 'SYS',
scope => 'COMPREHENSIVE',
time_limit => 60,
task_name => 'test_sql_tuning',
description => 'Task to tune a query on emp');
END;
/
PL/SQL procedure successfully completed.
參數(shù)說(shuō)明:
bind_list:多個(gè)綁定變量以','逗號(hào)分隔。參數(shù)值一定要根據(jù)綁定變量對(duì)應(yīng)的列的類型書寫.如:emp.ename類型是VARCHAR2(10),那么就要寫成 bind_list =>sql_binds(anydata.convertvarchar2(10)),
time_limit:執(zhí)行的最長(zhǎng)時(shí)間,默認(rèn)是60。
scope:LIMITED,用大概1秒時(shí)間去優(yōu)化SQL語(yǔ)句,但是并不進(jìn)行SQL Profiling分析;COMPREHENSIVE,進(jìn)行全面分析,包含SQL Profiling分析;比LIMITED用時(shí)更長(zhǎng)。
--查看任務(wù)名
SQL> select task_name from dba_advisor_log where task_name='test_sql_tuning';
TASK_NAME
------------------------------
test_sql_tuning
--執(zhí)行sql tuning任務(wù)
SQL> exec DBMS_SQLTUNE.EXECUTE_TUNING_TASK( task_name => 'test_sql_tuning' );
PL/SQL procedure successfully completed.
--查看sql tunning任務(wù)狀態(tài)
SQL> select task_name,status from dba_advisor_log where task_name='test_sql_tuning';
TASK_NAME STATUS
------------------------------ -----------
test_sql_tuning COMPLETED
----展示sql tunning結(jié)果
set long 10000
set longchunksize 1000
set linesize 100
select dbms_sqltune.report_tuning_task('test_sql_tuning') from dual;
...........省略
--根據(jù)建議accept_sql_profile
execute dbms_sqltune.accept_sql_profile(.....)
--完成后刪除sql tunning任務(wù)
exec dbms_sqltune.drop_tuning_task('test_sql_tuning');
--查看SQL Tuning Advisor的進(jìn)展(task執(zhí)行很久)
set lines 200
col opname for a20
col ADVISOR_NAME for a20
select sid,serial#,username,opname,advisor_name,target_desc,start_time sofar,totalwork from v$advisor_progress where username = 'SYS';
三、coe_xfr_sql_profile.sql固定執(zhí)行計(jì)劃(也是生成sql_profile)
--環(huán)境構(gòu)建,建立測(cè)試表,與outline測(cè)試一樣
create table zw as select * from dba_objects where object_id is not null;
alter table zw modify object_id not null; --索引不存儲(chǔ)null值
create index idx_zw_obj_id on zw(object_id);
analyze table zw compute statistics;
select count(*) from zw;
COUNT(*)
----------
87038
SQL> select * from table(dbms_xplan.display_cursor(null,0));
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------
SQL_ID 1f5n0rapts695, child number 0
-------------------------------------
select count(*) from zw
Plan hash value: 1836624960
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 54 (100)| |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_ZW_OBJ_ID | 87038 | 54 (0)| 00:00:01 |
-------------------------------------------------------------------------------
--使用hint提示,強(qiáng)制走全表,生成一個(gè)執(zhí)行計(jì)劃:
SQL> select /*+ full(zw) */ count(*)from zw;
COUNT(*)
----------
87038
SQL> select * from table(dbms_xplan.display_cursor(null,0));
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------
SQL_ID fp5ksbhww4594, child number 0
-------------------------------------
select /*+ full(zw) */ count(*)from zw
Plan hash value: 249608387
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 339 (100)| |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| ZW | 87038 | 339 (1)| 00:00:05 |
-------------------------------------------------------------------
14 rows selected.
--運(yùn)行coe_xfr_sql_profile腳本:(固定執(zhí)行計(jì)劃)
SQL> @coe_xfr_sql_profile.sql
Parameter 1:
SQL_ID (required)
Enter value for 1: 1f5n0rapts695 --原sql的sql_id
PLAN_HASH_VALUE AVG_ET_SECS
--------------- -----------
1836624960 .02
Parameter 2:
PLAN_HASH_VALUE (required)
Enter value for 2: 249608387 --想要選擇的執(zhí)行計(jì)劃的PLAN_HASH_VALUE值
Values passed to coe_xfr_sql_profile:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SQL_ID : "1f5n0rapts695"
PLAN_HASH_VALUE: "249608387"
SQL>BEGIN
2 IF :sql_text IS NULL THEN
3 RAISE_APPLICATION_ERROR(-20100, 'SQL_TEXT for SQL_ID &&sql_id. was not found in memory (gv$sqltext_with_newlines) or AWR (dba_hist_sqltext).');
4 END IF;
5 END;
6 /
SQL>SET TERM OFF;
SQL>BEGIN
2 IF :other_xml IS NULL THEN
3 RAISE_APPLICATION_ERROR(-20101, 'PLAN for SQL_ID &&sql_id. and PHV &&plan_hash_value. was not found in memory (gv$sql_plan) or AWR (dba_hist_sql_plan).');
4 END IF;
5 END;
6 /
SQL>SET TERM OFF;
Execute coe_xfr_sql_profile_1f5n0rapts695_249608387.sql
on TARGET system in order to create a custom SQL Profile
with plan 249608387 linked to adjusted sql_text.
COE_XFR_SQL_PROFILE completed.
SQL> @coe_xfr_sql_profile_1f5n0rapts695_249608387.sql
省略.................
coe_xfr_sql_profile_1f5n0rapts695_249608387 completed
SQL> explain plan for select count(*) from zw;
Explained.
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 249608387
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0| SELECT STATEMENT | | 1 | 312 (1)| 00:00:04 |
| 1| SORT AGGREGATE | | 1 | | |
| 2| TABLE ACCESS FULL| ZW | 87038 | 312 (1)| 00:00:04 |
-------------------------------------------------------------------
Note
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------
-SQL profile "coe_1f5n0rapts695_249608387"used for this statement
--查詢:
SQL> select name,category,status,sql_text fromdba_sql_profiles;
NAME CATEGORY STATUS SQL_TEXT
------------------------------ ------------ -------------------------------------------
coe_1f5n0rapts695_249608387 DEFAULE ENABLED select count(*) from zw
當(dāng)存在只有一個(gè)執(zhí)行計(jì)劃時(shí),而又不想讓應(yīng)用不改sql代碼的情況下改變執(zhí)行計(jì)劃,請(qǐng)參照自動(dòng)/手動(dòng)類型sql_profile(dbms_sqltune/coe_xfr_sql_profile.sql)
使用coe_xfr_sql_profile.sql固定計(jì)劃是不是很好用呢?是的,這一切都?xì)w功于oracle mos上的功勞,需要的童鞋可以到matelink上查找和下載。還有其它兩個(gè)有關(guān)的腳本:coe_load_sql_baseline.sql,coe_load_sql_profile.sql,有興趣的童鞋可以一起下載研究。
思考:當(dāng)在使用SQL_PROFILE綁定之前,使用了OUTLINE進(jìn)行固定的話,誰(shuí)的優(yōu)先級(jí)高呢?
根據(jù)網(wǎng)上的一些資料說(shuō)是OUTLINE的優(yōu)先級(jí)最高,但都是簡(jiǎn)短的一句話,沒有證明??墒墙?jīng)過我無(wú)數(shù)次的測(cè)試,發(fā)現(xiàn)都是SQL_PROFILE的優(yōu)先級(jí)較高,具體相關(guān)測(cè)試結(jié)果我就不粘貼出來(lái)了。(或許是我測(cè)試語(yǔ)句的特殊性,需再進(jìn)一步驗(yàn)證)
值得一提的是,sql_profile并不會(huì)以outline方式存儲(chǔ)凍結(jié)執(zhí)行計(jì)劃,當(dāng)表中數(shù)據(jù)增長(zhǎng)或索引被刪除或重建時(shí),在sql_profile不變的情況下執(zhí)行計(jì)劃也可以發(fā)生變化,信息的存儲(chǔ)和與數(shù)據(jù)的分布或者訪問路徑有關(guān)。
四、SQL PLAN MANAGE(baseline)
1、從11g開始,oracle引入了SQL執(zhí)行計(jì)劃管理(SQLPlan Management)這個(gè)新特性,與Oracle 9i 的outline和10g 的profile相比,Oracle 11g的SPM相對(duì)更加的靈活,允許你同時(shí)接受多個(gè)執(zhí)行計(jì)劃。
2、使用SQL PlanManagement固定執(zhí)行計(jì)劃
--一條帶有綁定變量的SQL語(yǔ)句,但數(shù)據(jù)分布不均,嚴(yán)重傾斜時(shí),最好的執(zhí)行計(jì)劃會(huì)根據(jù)綁定變量的值而不同。執(zhí)行時(shí),根據(jù)不同的變量值,SPM會(huì)花費(fèi)很少的運(yùn)算從中選擇一條最合適的。
SQL> select id,count(*) from test group by id order by 2;
ID COUNT(*)
---------- ----------
10 1100
88 10100
999 1000000
--接下來(lái)定義一個(gè)變量a,分別賦值999和10,看它的執(zhí)行計(jì)劃是如何的
SQL>alter system flush shared_pool;
SQL>var a1 number;
SQL>exec :a1:=999;
SQL>select t.* from test t wheret.id=:a1;
1000000 rows selected.
Elapsed: 00:00:25.30
SQL> select * from table(dbms_xplan.display_cursor(null,0));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID cpsdn05zdq02p,child number 0
-------------------------------------
select t.* from test t where t.id=:a1
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 424 (100)| |
|* 1| TABLE ACCESS FULL| TEST | 337K| 1316K| 424 (2)| 00:00:06 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified byoperation id):
---------------------------------------------------
1- filter("T"."ID"=:A1)
-##########################ID列上有個(gè)索引IDX_ID ################################
SQL>alter system flush shared_pool;
SQL>var a1 number;
SQL>exec :a1:=10;
SQL>select t.* from test t wheret.id=:a1;
1100 rows selected.
Elapsed: 00:00:00.04
SQL> select * fromtable(dbms_xplan.display_cursor(null,0));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID cpsdn05zdq02p,child number 0
-------------------------------------
select t.* from test t where t.id=:a1
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 424 (100)| |
|* 1| TABLE ACCESS FULL| TEST | 337K| 1316K| 424 (2)| 00:00:06 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified byoperation id):
---------------------------------------------------
1- filter("T"."ID"=:A1)
--這里可以看到,無(wú)論賦值是999還是10,其執(zhí)行計(jì)劃都是一樣的,但根據(jù)理論來(lái)說(shuō),我們都知道,id=10時(shí)走索引效率是最好的。假設(shè)數(shù)據(jù)是均勻分布的,那么基數(shù)評(píng)估cardinality=density*num_rows。Density可通過user_tab_col_statistics查詢。
select column_name,num_distinct,density from user_tab_col_statistics where table_name='TEST';
COLUMN_NAME NUM_DISTINCT DENSITY
------------------------------ ------------- ---------
ID 3 .333333333
--我們看到的Rows列預(yù)估的337k就是cardinality=density*num_rows=0.3333*1011200約等于337k行,
--但是我們都知道ID=10只有1100行,而ID=999有1000000行,所以當(dāng)ID=10的時(shí)候走索引全掃描,ID=999的時(shí)候走全表掃描是最合理的執(zhí)行計(jì)劃。
那么面對(duì)這種情況,我們?cè)撊绾巫屵@種情況下的執(zhí)行計(jì)劃達(dá)到最優(yōu)呢?方法有如下幾個(gè):
--1、去除綁定變量,直接硬解析的方式(非理想的,如果涉及要該程序代碼這是很不可取的)
--2、啟用11g的新特性ACS(自適應(yīng)游標(biāo),這個(gè)BUG不是一般的多,不建議啟用)
--3、收集直方圖信息(如果在生產(chǎn)高峰期,收集直方圖信息所占資源無(wú)法評(píng)估)
--4、使用SPM把不同的執(zhí)行計(jì)劃加入到SQLPlan Baseline中。
--使用手工捕獲的方式
alter system flush shared_pool;
var a1 number;
exec :a1:=999;
select t.* from test t where t.id=:a1;
select * fromtable(dbms_xplan.display_cursor(null,0));
var temp varchar2(1000);
exec :temp:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'cpsdn05zdq02p');
exec :temp :=dbms_spm.alter_sql_plan_baseline(sql_handle=>'SQL_d230ce970caa0077',plan_name=>'SQL_PLAN_d4c6fkw6an03r97bbe3d0',attribute_name=>'ENABLED',attribute_value=>'NO'); --先修改全表掃描的sql planbaselines的enabled屬性為NO,不然捕獲不了索引的。
exec :a1:=10;
select t.* from test t where t.id=:a1;
select * fromtable(dbms_xplan.display_cursor(null,0));
exec :temp:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'cpsdn05zdq02p');
dbms_spm.alter_sql_plan_baseline(sql_handle=>'SQL_d230ce970caa0077',plan_name=>'SQL_PLAN_d4c6fkw6an03r97bbe3d0',attribute_name=>'ENABLED',attribute_value=>'YES');
SQL> select sql_handle,plan_name,origin,enabled,accepted,fixed from dba_sql_plan_baselines;
SQL_HANDLE PLAN_NAME ORIGIN ENA ACC FIX
-------------------------------------------------- -------------- --- --- ---
SQL_d230ce970caa0077SQL_PLAN_d4c6fkw6an03r97bbe3d0 MANUAL-LOAD YES YES NO
SQL_d230ce970caa0077SQL_PLAN_d4c6fkw6an03rf98b55bb MANUAL-LOAD YES YES NO
--驗(yàn)證結(jié)果:
SQL> var a1 number;
SQL> exec :a1:=10;
SQL> select t.* from test t wheret.id=:a1;
SQL> select * fromtable(dbms_xplan.display_cursor(null,0));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID cpsdn05zdq02p,child number 0
-------------------------------------
select t.* from test t where t.id=:a1
Plan hash value: 578627003
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 5(100)| |
|* 1| INDEX RANGE SCAN| IDX_ID | 1280 | 5120 | 5 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified byoperation id):
---------------------------------------------------
1- access("T"."ID"=:A1)
Note
-----
-SQL plan baseline SQL_PLAN_d4c6fkw6an03rf98b55bbused for this statement
22 rows selected.
SQL> var a1 number;
SQL> exec :a1:=999;
SQL> select t.* from test t wheret.id=:a1;
SQL> select * fromtable(dbms_xplan.display_cursor(null,0));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID cpsdn05zdq02p,child number 0
-------------------------------------
select t.* from test t where t.id=:a1
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0| SELECT STATEMENT | | | | 424 (100)| |
|* 1| TABLE ACCESS FULL| TEST | 1001K| 3912K| 424 (2)| 00:00:06 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified byoperation id):
---------------------------------------------------
1- filter("T"."ID"=:A1)
Note
-----
-SQL plan baseline SQL_PLAN_d4c6fkw6an03r97bbe3d0used for this statement
22 rows selected.
SPM的靈活之處在于,可以動(dòng)態(tài)管理,不像存儲(chǔ)大綱(stored outline)和SQL Profile需要DBA手工創(chuàng)建,當(dāng)然SPM也可以,因?yàn)槲以谝陨涎菔局幸矝]讓它自動(dòng)捕獲。
思考:1、何種情況下使用什么固定執(zhí)行計(jì)劃的方法更加有效?2、在各種固定執(zhí)行計(jì)劃都使用的情況下,那種優(yōu)先級(jí)更高?
新聞名稱:執(zhí)行計(jì)劃綁定
文章路徑:http://www.dlmjj.cn/article/jsejii.html


咨詢
建站咨詢
