2009-07-06 3 views
1

donné ce tableau:Existe-t-il un meilleur moyen de rechercher sur une plage de valeurs dans Oracle que de tester une sous-requête?

x y 
-- - 
10 a 
20 b 
30 c 

Je veux la meilleure façon de cartographier les valeurs de

[10,20) -> a 
[20,30) -> b 
[30,inf) -> c 

En ce moment je suis en utilisant une requête comme:

select y from foo 
where x=(select max(x) from foo 
      where x<=21); 

Y at-il une meilleure façon de le faire? Y a-t-il une fonction analytique qui pourrait aider?

Voici mon cas de test:

create table foo as 
select 10 as x ,'a' as y from dual union 
select 20,'b' from dual union 
select 30,'c' from dual; 

-- returns: a,b,b: 
select y from foo where x=(select max(x) from foo where x<=19); 
select y from foo where x=(select max(x) from foo where x<=20); 
select y from foo where x=(select max(x) from foo where x<=21); 

Répondre

3

Vous pouvez réécrire votre requête pour accéder uniquement à la table foo une fois au lieu de deux fois, en utilisant la fonction d'agrégation MAX-KEEP.

Un exemple:

SQL> var N number 
SQL> exec :N := 19 

PL/SQL-procedure is geslaagd. 

SQL> select max(y) keep (dense_rank last order by x) y 
    2 from foo 
    3 where x <= :N 
    4/

Y 
- 
a 

1 rij is geselecteerd. 

SQL> exec :N := 20 

PL/SQL-procedure is geslaagd. 

SQL> select max(y) keep (dense_rank last order by x) y 
    2 from foo 
    3 where x <= :N 
    4/

Y 
- 
b 

1 rij is geselecteerd. 

SQL> exec :N := 21 

PL/SQL-procedure is geslaagd. 

SQL> select max(y) keep (dense_rank last order by x) y 
    2 from foo 
    3 where x <= :N 
    4/

Y 
- 
b 

1 rij is geselecteerd. 

Aussi a, b, b à la suite. Les plans de requête:

SQL> set serveroutput off 
SQL> select /*+ gather_plan_statistics */ 
    2   y 
    3 from foo 
    4 where x = (select max(x) from foo where x<=:N) 
    5/

Y 
- 
b 

1 rij is geselecteerd. 

SQL> select * from table(dbms_xplan.display_cursor(null,null,'predicate -note last')) 
    2/

PLAN_TABLE_OUTPUT 
------------------------------------------------------------------------------------------- 
SQL_ID 3kh85qqnb2phy, child number 0 
------------------------------------- 
select /*+ gather_plan_statistics */  y from foo where x = 
(select max(x) from foo where x<=:N) 

Plan hash value: 763646971 

---------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
---------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  |  |  8 (100)|   | 
|* 1 | TABLE ACCESS FULL | FOO |  1 | 16 |  4 (0)| 00:00:01 | 
| 2 | SORT AGGREGATE |  |  1 | 13 |   |   | 
|* 3 | TABLE ACCESS FULL| FOO |  2 | 26 |  4 (0)| 00:00:01 | 
---------------------------------------------------------------------------- 

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

    1 - filter("X"=) 
    3 - filter("X"<=:N) 


22 rijen zijn geselecteerd. 

SQL> select max(y) keep (dense_rank last order by x) y 
    2 from foo 
    3 where x <= :N 
    4/

Y 
- 
b 

1 rij is geselecteerd. 

SQL> select * from table(dbms_xplan.display_cursor(null,null,'predicate -note last')) 
    2/

PLAN_TABLE_OUTPUT 
------------------------------------------------------------------------------------------- 
SQL_ID avm2zh62c8cwd, child number 0 
------------------------------------- 
select max(y) keep (dense_rank last order by x) y from foo where x 
<= :N 

Plan hash value: 3274996510 

--------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  |  |  4 (100)|   | 
| 1 | SORT AGGREGATE |  |  1 | 16 |   |   | 
|* 2 | TABLE ACCESS FULL| FOO |  1 | 16 |  4 (0)| 00:00:01 | 
--------------------------------------------------------------------------- 

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

    2 - filter("X"<=:N) 


20 rijen zijn geselecteerd. 

Deux analyses complètes de table sur foo, contre un pour la nouvelle requête.

Cordialement, Rob.

+0

Ah, parfait. Les tests sur mon ensemble de données complet montrent une amélioration similaire ... merci! –

1
select distinct first_value(y) over (order by x desc) from foo where x<=19; 
select distinct first_value(y) over (order by x desc) from foo where x<=20; 
select distinct first_value(y) over (order by x desc) from foo where x<=21; 

Plus: un index sur x sera probablement une bonne idée.

1

Voici une autre réponse reçue via usenet. Jusqu'à présent, celui-ci semble avoir l'exécution la plus efficace.

select max(y) keep (dense_rank last order by x) from foo where x<=21; 
Questions connexes