使用 sql_profile 固定SQL执行计划
Table of Contents
1 扯蛋
近日 ,每天晚上固定时间,数据库会出现大量的latch:cache buffer chains 等待。经查 看发现原SQL语句走错执行计划,240G的表,进行全表扫描,引起热点块争用。通过固定 SQL语句的执行计划,使其可正常使用索引扫描,可以将该问题解决。下面为操作过程.
2 利用SQL PROFILE固定执行计划
2.1 查看原来语句的执行计划
SQL> set autotrace traceonly SQL> SELECT NODEID 2 FROM ICDMIP.LHB_TEST T WHERE --T.INANITIONID is null AND 3 4 PARTID = SUBSTR(201302130046087636, 5, 4) 5 ; 596762 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 514708567 ---------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 412K| 10M| 3513 (1)| 00:00:43 | | | | 1 | PARTITION LIST SINGLE| | 412K| 10M| 3513 (1)| 00:00:43 | 44 | 44 | | 2 | TABLE ACCESS FULL | LHB_TEST | 412K| 10M| 3513 (1)| 00:00:43 | 44 | 44 | --这里发现走的全表扫描,全表有240G,引起性能问题 ---------------------------------------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 54997 consistent gets --严重的逻辑读,SQL语句性能低下 580 physical reads 0 redo size 20489108 bytes sent via SQL*Net to client 438116 bytes received via SQL*Net from client 39786 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 596762 rows processed SQL> set autotrace off SQL> alter session set current_schema=ICDMIP; Session altered.
2.2 指定SQL使用选择性比较好的索引
提前已查看,条件PARTID可以使用索引PK_MIP_OPERATIONPROCESS.来试试,使用这个索引后,执行计划怎么样。
SQL> explain plan for SELECT/*+ INDEX(T PK_MIP_OPERATIONPROCESS)*/ NODEID 2 FROM ICDMIP.LHB_TEST T 3 WHERE T.INANITIONID = :B2 4 AND PARTID = SUBSTR(:B1, 5, 4); Explained. SQL> set linesize 500 pages 900 SQL> select * from table(dbms_xplan.display(null,null,‘outline‘); select * from table(dbms_xplan.display(null,null,‘outline‘) * ERROR at line 1: ORA-00907: missing right parenthesis SQL> a ) 1* select * from table(dbms_xplan.display(null,null,‘outline‘)) SQL> / PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Plan hash value: 1671553065 ------------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ------------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 44 | 4 (0)| 00:00:01 | | | | 1 | PARTITION LIST SINGLE | | 1 | 44 | 4 (0)| 00:00:01 | KEY | KEY | | 2 | TABLE ACCESS BY LOCAL INDEX ROWID| LHB_TEST | 1 | 44 | 4 (0)| 00:00:01 | KEY | KEY | |* 3 | INDEX UNIQUE SCAN | PK_MIP_OPERATIONPROCESS | 1 | | 3 (0)| 00:00:01 | KEY | KEY | --SQL已使用相关索引 ------------------------------------------------------------------------------------------------------------------------------ Outline Data ------------- /*+ BEGIN_OUTLINE_DATA INDEX_RS_ASC(@"SEL$1" "T"@"SEL$1" ("LHB_TEST"."INANITIONID" "LHB_TEST"."PARTID")) OUTLINE_LEAF(@"SEL$1") ALL_ROWS OPT_PARAM(‘optimizer_dynamic_sampling‘ 1) OPTIMIZER_FEATURES_ENABLE(‘10.2.0.3‘) IGNORE_OPTIM_EMBEDDED_HINTS END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("T"."INANITIONID"=:B2 AND "PARTID"=SUBSTR(:B1,5,4)) 29 rows selected.
2.3 生成sql profile
注意对比第二步中‘Outline Data‘ 数据与本步骤中sys.sqlprof_attr内容的关系
SQL> declare 2 v_hints sys.sqlprof_attr; 3 begin 4 v_hints := sys.sqlprof_attr( 5 ‘BEGIN_OUTLINE_DATA‘, 6 ‘IGNORE_OPTIM_EMBEDDED_HINTS‘, 7 ‘OPTIMIZER_FEATURES_ENABLE(‘‘10.2.0.3‘‘)‘, 8 ‘DB_VERSION(‘‘10.2.0.3‘‘)‘, 9 ‘ALL_ROWS‘, 10 ‘OUTLINE_LEAF(@"SEL$1")‘, 11 ‘INDEX_RS_ASC(@"SEL$1" "T"@"SEL$1" ("LHB_TEST"."INANITIONID" "LHB_TEST"."PARTID"))‘, 12 ‘END_OUTLINE_DATA‘); 13 dbms_sqltune.import_sql_profile( 14 ‘SELECT NODEID FROM ICDMIP.LHB_TEST T WHERE T.INANITIONID = :B2 AND PARTID = SUBSTR(:B1, 5, 4)‘, 15 v_hints, 16 ‘SQLPROFILE_T_M_O‘, --sql profile 名称 17 force_match=>true, 18 replace=>true); 19 end; 20 / PL/SQL procedure successfully completed.
2.4 验证sql profile 是否生效
SQL> explain plan for SELECT NODEID FROM ICDMIP.LHB_TEST T WHERE T.INANITIONID = :B2 AND PARTID = SUBSTR(:B1, 5, 4); Explained. SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Plan hash value: 1671553065 ------------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ------------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 44 | 4 (0)| 00:00:01 | | | | 1 | PARTITION LIST SINGLE | | 1 | 44 | 4 (0)| 00:00:01 | KEY | KEY | | 2 | TABLE ACCESS BY LOCAL INDEX ROWID| LHB_TEST | 1 | 44 | 4 (0)| 00:00:01 | KEY | KEY | |* 3 | INDEX UNIQUE SCAN | PK_MIP_OPERATIONPROCESS | 1 | | 3 (0)| 00:00:01 | KEY | KEY | ------------------------------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("T"."INANITIONID"=:B2 AND "PARTID"=SUBSTR(:B1,5,4)) Note ----- - SQL profile "SQLPROFILE_T_M_O" used for this statement--注意,当生效后,这里会提示sql profile已使用 19 rows selected. SQL> exit
- note
- 删除sql profile方法 exec dbms_sqltune.drop_sql_profile(name => ‘&sql_profile‘);