2014-12-02 63 views
3

数据库是例如Oracle人力资源数据库:http://elsasoft.com/samples/oracle/Oracle.XE.HR/default.htm如何创建一个产生这个解释计划的查询? (的Oracle SQL)

解释计划:

---------------------------------------------------------- 
| Id | Operation      | Name    | 
---------------------------------------------------------- 
| 0 | SELECT STATEMENT    |     | 
| 1 | HASH UNIQUE     |     | 
|* 2 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES   | 
|* 3 | INDEX RANGE SCAN   | EMP_DEPARTMENT_IX | 
---------------------------------------------------------- 

Predictate Information (identified by operation id): 
---------------------------------------------------- 

2 - filter("MANAGER_ID" < 150) 
3 - access("DEPARTMENT_ID" < 50) 

我尝试这个查询,但它产生了非常不同的结果:

select /*+ use_hash(emp) */* 
    from HR.employees emp 
where MANAGER_ID <150 and 
     DEPARTMENT_ID <50; 

我已经建立了filteraccess的where语句。并从HASH_UNIQUEuse_hash。但结果仍然是非常不同的,我不知道如何解决它

+4

的'HASH UNIQUE'指示存在一个'distinct'或可能'by'涉及 – 2014-12-02 11:39:13

+0

我试图SELECT DISTINCT'EMPLOYEE_ID组'from ...但仍然不是UNIQUE_ID – 2014-12-02 11:52:44

+0

请尝试像@JonHeller的回答,以区别'first_name'或另一个非索引列。 – 2014-12-08 14:11:20

回答

4

创建一个精确的解释计划是困难的,取决于查询,版本,参数和无证提示。

在这种情况下,主要提示可能是未公开的USE_HASH_AGGREGATION,但它也必须与DISTINCTGROUP BY结合使用。但是它也取决于使用哪个列 - 如果查询只对主键做了明确的分析,那么它不会聚合,因为优化器知道没有必要。

由于我使用12c,我必须禁用_optimizer_batch_table_access_by_rowid,但这对于早期版本不是必需的。

无证件format => '+outline'功能有助于创建精确的计划。如果你不使用12c,很难保证它能以相同的方式工作。 This SQL Fiddle适用于11gR2,但很难知道提示是否有效,或者计划是否相同。

查询

explain plan for 
select 
    /*+ 
     BEGIN_OUTLINE_DATA 
     USE_HASH_AGGREGATION(@"SEL$1") 
     INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMPLOYEES"."DEPARTMENT_ID")) 
     OUTLINE_LEAF(@"SEL$1") 
     ALL_ROWS 
     OPT_PARAM('_optimizer_batch_table_access_by_rowid' 'false') 
     DB_VERSION('12.1.0.1') 
     OPTIMIZER_FEATURES_ENABLE('12.1.0.1') 
     IGNORE_OPTIM_EMBEDDED_HINTS 
     END_OUTLINE_DATA 
    */ 
    distinct first_name 
from HR.employees emp 
where MANAGER_ID <150 and 
    DEPARTMENT_ID <50; 

计划

select * from table(dbms_xplan.display(format => 'basic +predicate +outline')); 

Plan hash value: 2074795195 

---------------------------------------------------------- 
| Id | Operation     | Name    | 
---------------------------------------------------------- 
| 0 | SELECT STATEMENT    |     | 
| 1 | HASH UNIQUE     |     | 
|* 2 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES   | 
|* 3 | INDEX RANGE SCAN   | EMP_DEPARTMENT_IX | 
---------------------------------------------------------- 

Outline Data 
------------- 

    /*+ 
     BEGIN_OUTLINE_DATA 
     USE_HASH_AGGREGATION(@"SEL$1") 
     INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMPLOYEES"."DEPARTMENT_ID")) 
     OUTLINE_LEAF(@"SEL$1") 
     ALL_ROWS 
     OPT_PARAM('_optimizer_batch_table_access_by_rowid' 'false') 
     DB_VERSION('12.1.0.1') 
     OPTIMIZER_FEATURES_ENABLE('12.1.0.1') 
     IGNORE_OPTIM_EMBEDDED_HINTS 
     END_OUTLINE_DATA 
    */ 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - filter("MANAGER_ID"<150) 
    3 - access("DEPARTMENT_ID"<50) 
+1

我通过从员工emp 中选择不同的姓氏 ,在我的12.1.0.2.0中获得了期望的计划,其中manager_id <150 和department_id <50'完全没有任何提示。我希望不同的first_name可以做同样的事情,或者实际上可以区分任何非索引列。 – 2014-12-08 14:09:04

2

先试着收集表上的统计,如果上述计划是有道理的,那么你会得到它

exec dbms_stats.gather_table_stats('HR','EMP', cascade=>true); 

如果你仍然没有得到这个计划,然后甲骨文认为有一个更好的计划(他通常是正确的)。 要强制该计划试图

select /*+ USE_INDEX(eMP,EMP_DEPARTMENT_IX) */ 
from HR.employees emp 
where MANAGER_ID <150 and DEPARTMENT_ID <50 
+0

谢谢。按索引rowid和索引范围扫描的表访问现在在计划中。只有'HASH UNIQUE'缺失 – 2014-12-02 11:46:26