1

我有以下带有指定有序索引提示的查询。我想知道我是否做错了什么,使它忽略了我的有序索引提示。

select /*+ ORDERED USE_NL (ptp payr) INDEX (ptp, PER_TIME_PERIODS_N50) INDEX (ppa, PAY_PAYROLL_ACTIONS_FK8) USE_NL (ppa ptp) USE_NL (ppa pcs) USE_NL (paa ppa) INDEX (prr2, PAY_RUN_RESULTS_N50) USE_NL (prr2 paa) INDEX (prr, PAY_RUN_RESULTS_N50) USE_NL (prr paa) */ 
       papf.employee_number, 
       papf.full_name, 
       ppos.date_start
from   pay_all_payrolls_f     payr,
       per_time_periods       ptp,
       pay_payroll_actions    ppa,
       pay_consolidation_sets pcs,
       pay_assignment_actions paa,
       per_all_assignments_f  paaf,
       per_all_people_f       papf,
       per_periods_of_service ppos
where  payr.attribute2 = 'N'  -- Non-Flexi aka Monthly
and    trunc(sysdate) between payr.effective_start_date and payr.effective_end_date
and    ptp.payroll_id = payr.payroll_id
and    trunc(sysdate) between ptp.start_date and ptp.end_date
and    ppa.time_period_id = ptp.time_period_id
and    ppa.action_type = 'R'
and    ppa.action_status = 'C'  
and    pcs.consolidation_set_id = ppa.consolidation_set_id
and    pcs.consolidation_set_name = 'Main Run' 
and    paa.payroll_action_id = ppa.payroll_action_id
and    paa.action_status = 'C'
and    paaf.assignment_id = paa.assignment_id
and    paaf.effective_start_date = 
(
   select max(paaf2.effective_start_date)
   from   per_all_assignments_f paaf2
   where  paaf2.assignment_id = paaf.assignment_id
   and    paaf2.effective_start_date <= ptp.end_date
)
and    papf.person_id = paaf.person_id
and    paaf.effective_start_date between papf.effective_start_date and papf.effective_end_date
and    ppos.period_of_service_id = paaf.period_of_service_id
and    not exists
(
   select *
   from   pay_element_types_f    petf,
          pay_input_values_f     pivf,
          pay_run_result_values  prrv,
          pay_run_results        prr
   where  petf.attribute1 = '401'  
   and    trunc(sysdate) between petf.effective_start_date and petf.effective_end_date
   and    pivf.element_type_id = petf.element_type_id
   and    pivf.name = 'Pay Value'
   and    trunc(sysdate) between pivf.effective_start_date and pivf.effective_end_date
   and    prrv.input_value_id = pivf.input_value_id
   and    prr.run_result_id = prrv.run_result_id
   and    prr.assignment_action_id = paa.assignment_action_id
)
and    exists
(
   select *
   from   pay_run_results prr2
   where  prr2.assignment_action_id = paa.assignment_action_id
)

解释计划如下:

Plan
SELECT STATEMENT  ALL_ROWSCost: 10 304 693  Bytes: 113 685  Cardinality: 583                                                        
    41 NESTED LOOPS                                                     
        39 NESTED LOOPS  Cost: 10 278 570  Bytes: 195  Cardinality: 1                                               
            37 NESTED LOOPS  Cost: 10 278 569  Bytes: 182  Cardinality: 1                                           
                34 NESTED LOOPS  Cost: 10 278 566  Bytes: 128  Cardinality: 1                                       
                    28 NESTED LOOPS  Cost: 10 278 552  Bytes: 742  Cardinality: 7                                   
                        13 NESTED LOOPS  Cost: 9 961 317  Bytes: 13 947 120  Cardinality: 158 490                               
                            10 NESTED LOOPS  Cost: 8 836 765  Bytes: 76 406 568  Cardinality: 1 123 626                             
                                7 NESTED LOOPS  Cost: 4 635 168  Bytes: 3 927 462 339  Cardinality: 74 103 063                          
                                    4 NESTED LOOPS  Cost: 890 613  Bytes: 52 268 552  Cardinality: 1 866 734                    
                                        2 SORT UNIQUE  Cost: 10 691  Bytes: 35 938 560  Cardinality: 5 989 760                  
                                            1 TABLE ACCESS FULL TABLE HR.PAY_RUN_RESULTS Cost: 10 691  Bytes: 35 938 560  Cardinality: 5 989 760            
                                        3 TABLE ACCESS FULL TABLE HR.PAY_ALL_PAYROLLS_F Cost: 4  Bytes: 176  Cardinality: 8                 
                                    6 TABLE ACCESS BY INDEX ROWID TABLE HR.PER_TIME_PERIODS Cost: 2  Bytes: 1 000  Cardinality: 40                      
                                        5 INDEX RANGE SCAN INDEX HR.PER_TIME_PERIODS_N50 Cost: 1  Cardinality: 40               
                                9 TABLE ACCESS BY INDEX ROWID TABLE HR.PAY_PAYROLL_ACTIONS Cost: 2  Bytes: 15  Cardinality: 1                       
                                    8 INDEX RANGE SCAN INDEX HR.PAY_PAYROLL_ACTIONS_FK8 Cost: 0  Cardinality: 1                     
                            12 TABLE ACCESS BY INDEX ROWID TABLE HR.PAY_CONSOLIDATION_SETS Cost: 1  Bytes: 20  Cardinality: 1                           
                                11 INDEX UNIQUE SCAN INDEX (UNIQUE) HR.PAY_CONSOLIDATION_SETS_PK Cost: 0  Cardinality: 1                        
                        27 TABLE ACCESS BY INDEX ROWID TABLE HR.PAY_ASSIGNMENT_ACTIONS Cost: 2  Bytes: 18  Cardinality: 1                               
                            26 INDEX UNIQUE SCAN INDEX (UNIQUE) HR.PAY_ASSIGNMENT_ACTIONS_PK Cost: 1  Cardinality: 1                            
                                25 NESTED LOOPS                         
                                    23 NESTED LOOPS  Cost: 88  Bytes: 83  Cardinality: 1                    
                                        21 HASH JOIN  Cost: 86  Bytes: 60  Cardinality: 1               
                                            19 NESTED LOOPS             
                                                17 NESTED LOOPS  Cost: 68  Bytes: 3 102  Cardinality: 141       
                                                    15 TABLE ACCESS BY INDEX ROWID TABLE HR.PAY_RUN_RESULTS Cost: 6  Bytes: 300  Cardinality: 25    
                                                        14 INDEX RANGE SCAN INDEX HR.PAY_RUN_RESULTS_N50 Cost: 3  Cardinality: 25  
                                                    16 INDEX RANGE SCAN INDEX HR.PAY_RUN_RESULT_VALUES_N50 Cost: 2  Cardinality: 6      
                                                18 TABLE ACCESS BY INDEX ROWID TABLE HR.PAY_RUN_RESULT_VALUES Cost: 3  Bytes: 60  Cardinality: 6        
                                            20 TABLE ACCESS FULL TABLE HR.PAY_INPUT_VALUES_F Cost: 17  Bytes: 152  Cardinality: 4           
                                        22 INDEX RANGE SCAN INDEX (UNIQUE) HR.PAY_ELEMENT_TYPES_F_PK Cost: 1  Cardinality: 1                
                                    24 TABLE ACCESS BY INDEX ROWID TABLE HR.PAY_ELEMENT_TYPES_F Cost: 2  Bytes: 23  Cardinality: 1                      
                    33 TABLE ACCESS BY INDEX ROWID TABLE HR.PER_ALL_ASSIGNMENTS_F Cost: 2  Bytes: 22  Cardinality: 1                                    
                        32 INDEX RANGE SCAN INDEX (UNIQUE) HR.PER_ASSIGNMENTS_F_PK Cost: 1  Cardinality: 1                                  
                            31 SORT AGGREGATE  Bytes: 13  Cardinality: 1                            
                                30 FIRST ROW  Cost: 2  Bytes: 13  Cardinality: 1                        
                                    29 INDEX RANGE SCAN (MIN/MAX) INDEX (UNIQUE) HR.PER_ASSIGNMENTS_F_PK Cost: 2  Bytes: 13  Cardinality: 1                     
                36 TABLE ACCESS BY INDEX ROWID TABLE HR.PER_ALL_PEOPLE_F Cost: 3  Bytes: 54  Cardinality: 1                                         
                    35 INDEX RANGE SCAN INDEX (UNIQUE) HR.PER_PEOPLE_F_PK Cost: 1  Cardinality: 1                                   
            38 INDEX UNIQUE SCAN INDEX (UNIQUE) HR.PER_PERIODS_OF_SERVICE_PK Cost: 0  Cardinality: 1                                            
        40 TABLE ACCESS BY INDEX ROWID TABLE HR.PER_PERIODS_OF_SERVICE Cost: 1  Bytes: 13  Cardinality: 1                                   

我希望它从 pay_assignment_actions 表转到 pay_run_results 表,但它先去那里并对其进行全表扫描;完全无视我的暗示,表现糟糕。有人知道为什么或如何解决这个问题吗?

4

1 回答 1

1

如果索引位于内联视图或子查询中,则需要在索引提示中引用查询块名称。您可以使用自动生成的查询块名称,也可以使用qb_name提示自行创建。

在此处输入图像描述

示例架构和数据

create table pay_assignment_actions
(
    assignment_action_id number,
    some_other_column number
);

create table pay_run_results
(
    assignment_action_id number,
    some_other_column number
);
create index PAY_RUN_RESULTS_N50 on pay_run_results(assignment_action_id);

insert into pay_assignment_actions
    select level, level from dual connect by level <= 100000;
insert into pay_run_results
    select level, level from dual connect by level <= 100000;
begin
    dbms_stats.gather_table_stats(user, 'pay_assignment_actions');
    dbms_stats.gather_table_stats(user, 'pay_run_results');
end;
/

默认计划:无索引,使用alias格式查找查询块名称

explain plan for
select *
from pay_assignment_actions paa
where exists
(
    select *
    from pay_run_results prr
    where prr.assignment_action_id = paa.assignment_action_id
        --to stop the default plan from using an index
        and some_other_column = 5
);

select * from table(dbms_xplan.display(format => 'alias -predicate'));

Plan hash value: 1799975253

-----------------------------------------------------------------------------------------------
| Id  | Operation            | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                        |     1 |    20 |   139   (3)| 00:00:01 |
|   1 |  HASH JOIN RIGHT SEMI|                        |     1 |    20 |   139   (3)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | PAY_RUN_RESULTS        |     1 |    10 |    69   (2)| 00:00:01 |
|   3 |   TABLE ACCESS FULL  | PAY_ASSIGNMENT_ACTIONS |   100K|   976K|    69   (2)| 00:00:01 |
-----------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$5DA710D3
   2 - SEL$5DA710D3 / PRR@SEL$2
   3 - SEL$5DA710D3 / PAA@SEL$1

使用自动生成的查询块名称强制索引

explain plan for
select /*+ index(@SEL$2 prr) */ *
from pay_assignment_actions paa
where exists
(
    select *
    from pay_run_results prr
    where prr.assignment_action_id = paa.assignment_action_id
        --to stop the default plan from using an index
        and some_other_column = 5
);

select * from table(dbms_xplan.display(format => '-predicate'));

Plan hash value: 1805560573

-------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                        |     1 |    20 |   476   (1)| 00:00:01 |
|   1 |  HASH JOIN RIGHT SEMI        |                        |     1 |    20 |   476   (1)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| PAY_RUN_RESULTS        |     1 |    10 |   406   (1)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | PAY_RUN_RESULTS_N50    |   100K|       |   201   (1)| 00:00:01 |
|   4 |   TABLE ACCESS FULL          | PAY_ASSIGNMENT_ACTIONS |   100K|   976K|    69   (2)| 00:00:01 |
-------------------------------------------------------------------------------------------------------

使用 QB_NAME 制作您自己的查询块名称

explain plan for
select /*+ index(@my_subquery prr) */ *
from pay_assignment_actions paa
where exists
(
    select /*+ qb_name(my_subquery) */ *
    from pay_run_results prr
    where prr.assignment_action_id = paa.assignment_action_id
        --to stop the default plan from using an index
        and some_other_column = 5
);

select * from table(dbms_xplan.display(format => 'alias -predicate'));

Plan hash value: 1805560573

-------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                        |     1 |    20 |   476   (1)| 00:00:01 |
|   1 |  HASH JOIN RIGHT SEMI        |                        |     1 |    20 |   476   (1)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| PAY_RUN_RESULTS        |     1 |    10 |   406   (1)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | PAY_RUN_RESULTS_N50    |   100K|       |   201   (1)| 00:00:01 |
|   4 |   TABLE ACCESS FULL          | PAY_ASSIGNMENT_ACTIONS |   100K|   976K|    69   (2)| 00:00:01 |
-------------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$08BA3066
   2 - SEL$08BA3066 / PRR@MY_SUBQUERY
   3 - SEL$08BA3066 / PRR@MY_SUBQUERY
   4 - SEL$08BA3066 / PAA@SEL$1

当对象跨越查询块时使用 USE_NL

不同查询块中的对象可以通过它们的完整对象别名来引用,如下所示:

explain plan for
select /*+ index(@SEL$2 prr) use_nl(prr@sel$2 paa@sel$1) */ *
from pay_assignment_actions paa
where exists
(
    select *
    from pay_run_results prr
    where prr.assignment_action_id = paa.assignment_action_id
        --to stop the default plan from using an index
        and some_other_column = 5
);

select * from table(dbms_xplan.display(format => '-predicate'));

Plan hash value: 2326545440

--------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                        |     1 |    20 |   476   (1)| 00:00:06 |
|   1 |  NESTED LOOPS                 |                        |     1 |    20 |   476   (1)| 00:00:06 |
|   2 |   SORT UNIQUE                 |                        |     1 |    10 |   406   (1)| 00:00:05 |
|   3 |    TABLE ACCESS BY INDEX ROWID| PAY_RUN_RESULTS        |     1 |    10 |   406   (1)| 00:00:05 |
|   4 |     INDEX FULL SCAN           | PAY_RUN_RESULTS_N50    |   100K|       |   201   (1)| 00:00:03 |
|   5 |   TABLE ACCESS FULL           | PAY_ASSIGNMENT_ACTIONS |     1 |    10 |    69   (2)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
于 2013-09-05T05:46:41.143 回答