在测试执行计划、SQL优化、对比不同执行计划的效率时,让Oracle产生预期的执行计划还是很有意义的。
前两天在PUB上看到一个帖子,问为什么一个查询没有产生INDEX_JOIN执行计划。http://www.itpub.net/showthread.php?s=&threadid=829318
这里就以INDEX_JOIN为例,简单描述一下如何影响Oracle的执行计划的产生。
介绍通过修改表中数据来产生预期的执行计划。
如何让Oracle产生预期的执行计划(一):http://yangtingkun.itpub.net/post/468/357542
如何让Oracle产生预期的执行计划(二): http://yangtingkun.itpub.net/post/468/364939
上两篇文章分别介绍了手工设置统计信息和修改表结构来达到预期的执行计划。这篇文章介绍通过修改表中的数据的方法,使得Oracle得到预期的执行计划。
首先还是重建测试表:
SQL> DROP TABLE EMPLOYEES;
表已丢弃。
SQL> CREATE TABLE EMPLOYEES AS SELECT * FROM HR.EMPLOYEES;
表已创建。
SQL> ALTER TABLE EMPLOYEES ADD CONSTRAINT PK_EMPLOYEES PRIMARY KEY (EMPLOYEE_ID);
表已更改。
SQL> CREATE INDEX IND_EMP_SALARY ON EMPLOYEES (SALARY);
索引已创建。
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'EMPLOYEES', CASCADE => TRUE)
PL/SQL 过程已成功完成。
SQL> SET AUTOT TRACE
SQL> SELECT EMPLOYEE_ID, SALARY
2 FROM EMPLOYEES
3 WHERE SALARY > 2000;
已选择107行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=107 Bytes=856)
1 0 TABLE ACCESS (FULL) OF 'EMPLOYEES' (Cost=2 Card=107 Bytes=856)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
12 consistent gets
0 physical reads
0 redo size
2273 bytes sent via SQL*Net to client
580 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
107 rows processed
虽然使用不同的方法,但是思路仍然是一样的:使得表访问的代价增加。如果在不修改表结构,不人为设置统计信息的前提下,仅通过对数据进行修改,来提高表的访问代价,方法只能是通过构造行迁移。
下面先产生测试表,然后用尽量短的信息装载表,最后通过UPDATE将表的长度增加,认为的构造大量的行迁移,从而提高表的访问代价。
SQL> DELETE EMPLOYEES;
已删除107行。
SQL> INSERT INTO EMPLOYEES
2 SELECT A.EMPLOYEE_ID*1000 + B.EMPLOYEE_ID,
3 NULL, ' ', ' ', NULL, A.HIRE_DATE, ' ',
4 A.SALARY, NULL, NULL, NULL
5 FROM HR.EMPLOYEES A, HR.EMPLOYEES B;
已创建11449行。
SQL> UPDATE EMPLOYEES
2 SET FIRST_NAME = LPAD('1', 20, '1'), LAST_NAME = LPAD('1', 25, '1'), EMAIL = LPAD('1', 25, '1'),
3 PHONE_NUMBER = LPAD('1', 20, '1'), JOB_ID = LPAD('1', 10, '1'), COMMISSION_PCT = 0.99,
4 MANAGER_ID = 999999, DEPARTMENT_ID = 9999
5 ;
已更新11449行。
SQL> COMMIT;
提交完成。
下面重新收集统计信息:
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'EMPLOYEES')
PL/SQL 过程已成功完成。
SQL> SET AUTOT TRACE
SQL> SELECT EMPLOYEE_ID, SALARY
2 FROM EMPLOYEES
3 WHERE SALARY > 2000;
已选择11449行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=12 Card=11449 Bytes=103041)
1 0 VIEW OF 'index$_join$_001' (Cost=12 Card=11449 Bytes=103041)
2 1 HASH JOIN
3 2 INDEX (RANGE SCAN) OF 'IND_EMP_SALARY' (NON-UNIQUE) (Cost=39 Card=11449 Bytes=103041)
4 2 INDEX (FAST FULL SCAN) OF 'PK_EMPLOYEES' (UNIQUE) (Cost=39 Card=11449 Bytes=103041)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
854 consistent gets
0 physical reads
2088 redo size
207404 bytes sent via SQL*Net to client
8896 bytes received via SQL*Net from client
765 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
11449 rows processed
通过对表中数据进行修改,使得Oracle根据预期产生了INDEX_JOIN执行计划。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4227/viewspace-69392/ ,如需转载,请注明出处,否则将追究法律责任。