2009-07-22 7 views
0

je les tableaux ci-dessousOracle Optimisation des requêtes

Maître Tableau

id  
---- 
1x 
2x  

....

Affectation Tableau

id | type_id | assign_id 
----------------------------- 
1x | 2  | 554 
1x | 3  | 664 
2x | 2  | 919 
2x | 4  | 514 

table type

type_id | create_date 
---------------------- 
1  | 01/01/2009 
2  | 01/01/2009 
3  | 03/01/2009 
4  | 04/01/2009 

Ce que je dois pour la requête de sortie est quelque chose comme ça

id | max create_date type_id | assign_id 
    ---------------------------------------------- 
    1x | 3      | 664 
    2x | 4      | 514 

En ce moment je fais quelque chose comme ça pour acquérir les résultats, mais je suis sûr qu'il ya une bien meilleure façon de le faire .

Q1 
--- 
CREATE TABLE tmp_table as 
SELECT m.id, max(t.create_date) 
FROM master m, assignment a, type t 
WHERE m.id=a.id 
and a.type_id=t.type_id 
GROUP BY m.id 

Q2 
-- 
SELECT tmp.id, a.type_id, a.assign_id 
from tmp_table tmp, assignment a, type t 
WHERE tmp.create_date=t.create_date 
and t.type_id=a.type_id 

Merci pour toute aide

Répondre

4

Aucune table temporaire nécessaire.

select distinct 
     a.id, 
     first_value(t.type_id) 
     over (partition by a.id order by t.create_date desc) 
     as max_create_date_type_id, 
     first_value(a.assign_id) 
     over (partition by a.id order by t.create_date desc) 
     as assign_id 
from assignment a, type t 
where a.type_id = t.type_id 
+0

Merci jeffery. Je n'ai jamais entendu parler des commandes first_value et over. – AlteredConcept

+1

Rechercher "fonctions analytiques Oracle" - ils sont très puissants :) lecture recommandée: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions001.htm#i81407 –

+0

corrigé, après lire la réponse de Vincent. –

2

Si vous utilisez la libération Oracle9i 2 ou version ultérieure, vous pouvez utiliser la clause WITH. Ensuite, au lieu de devoir créer une table temporaire Q1 puis Q2, vous ne pouvez avoir qu'une seule instruction.

Non seulement la syntaxe sera plus courte, mais cela peut également améliorer la vitesse de la requête.

http://www.dba-oracle.com/t_with_clause.htm

Votre requête deviendrait quelque chose comme:

WITH tmp_table as (
SELECT m.id, max(t.create_date) 
FROM master m, assignment a, type t 
WHERE m.id=a.id 
and a.type_id=t.type_id 
GROUP BY m.id) 

SELECT tmp.id, a.type_id, a.assign_id 
from tmp_table tmp, assignment a, type t 
WHERE tmp.create_date=t.create_date 
and t.type_id=a.type_id 
2

vous pouvez utiliser l'analyse pour obtenir le résultat dans une requête:

SQL> WITH assignment_t AS (
    2  SELECT '1x' ID, 2 type_id, 554 assign_id FROM dual UNION ALL 
    3  SELECT '1x', 3, 664 FROM dual UNION ALL 
    4  SELECT '2x', 2, 919 FROM dual UNION ALL 
    5  SELECT '2x', 4, 514 FROM dual 
    6 ), type_t AS (
    7  SELECT 1 type_id, DATE '2009-01-01' create_date FROM dual UNION ALL 
    8  SELECT 2, DATE '2009-01-01' FROM dual UNION ALL 
    9  SELECT 3, DATE '2009-01-03' FROM dual UNION ALL 
10  SELECT 4, DATE '2009-01-04' FROM dual 
11 ) 
12 SELECT DISTINCT a.ID "id", 
13   first_value(a.type_id) 
14   OVER(PARTITION BY a.id 
15     ORDER BY t.create_date DESC) "max create_date type_id", 
16   first_value(a.assign_id) 
17   OVER(PARTITION BY a.id 
18     ORDER BY t.create_date DESC) "assign_id" 
19 FROM assignment_t a 
20 JOIN type_t t ON (a.type_id = t.type_id) 
21 ; 

id max create_date type_id assign_id 
-- ----------------------- ---------- 
2x      4  514 
1x      3  664 
3

En utilisant l'analyse, puis appliquer l'opérateur DISTINCT n'est pas la voie à suivre, lorsque vous avez besoin d'agréger.

Voici un simple et version plus performante en utilisant uniquement des agrégats:

SQL> select a.id 
    2  , max(t.type_id) keep (dense_rank last order by t.create_date) max_create_date_type_id 
    3  , max(a.assign_id) keep (dense_rank last order by t.create_date) assign_id 
    4 from assignment a 
    5  , type t 
    6 where a.type_id = t.type_id 
    7 group by a.id 
    8/

ID MAX_CREATE_DATE_TYPE_ID ASSIGN_ID 
-- ----------------------- ---------- 
1x      3  664 
2x      4  514 

2 rows selected. 

Et voici un test pour prouver qu'il est plus performant:

SQL> exec dbms_stats.gather_table_stats(user,'assignment') 

PL/SQL procedure successfully completed. 

SQL> exec dbms_stats.gather_table_stats(user,'type') 

PL/SQL procedure successfully completed. 

SQL> select /*+ gather_plan_statistics */ 
    2   distinct 
    3   a.id, 
    4   first_value(t.type_id) 
    5   over (partition by a.id order by t.create_date desc) 
    6   as max_create_date_type_id, 
    7   first_value(a.assign_id) 
    8   over (partition by a.id order by t.create_date desc) 
    9   as assign_id 
10 from assignment a, type t 
11 where a.type_id = t.type_id 
12/

ID MAX_CREATE_DATE_TYPE_ID ASSIGN_ID 
-- ----------------------- ---------- 
2x      4  514 
1x      3  664 

2 rows selected. 

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

PLAN_TABLE_OUTPUT 
------------------------------------------------------------------------------------------------------------------------- 

SQL_ID fu520w4kf2bbp, child number 0 
------------------------------------- 
select /*+ gather_plan_statistics */  distinct  a.id, 
first_value(t.type_id)  over (partition by a.id order by 
t.create_date desc)  as max_create_date_type_id, 
first_value(a.assign_id)  over (partition by a.id order by 
t.create_date desc)  as assign_id from assignment a, type t where 
a.type_id = t.type_id 

Plan hash value: 4160194652 

------------------------------------------------------------------------------------------------------------------------- 
| Id | Operation    | Name  | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | 
------------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT  |   |  1 |  |  2 |00:00:00.01 |  6 |  |  |   | 
| 1 | HASH UNIQUE   |   |  1 |  4 |  2 |00:00:00.01 |  6 | 898K| 898K| 493K (0)| 
| 2 | WINDOW SORT   |   |  1 |  4 |  4 |00:00:00.01 |  6 | 2048 | 2048 | 2048 (0)| 
| 3 | WINDOW SORT  |   |  1 |  4 |  4 |00:00:00.01 |  6 | 2048 | 2048 | 2048 (0)| 
|* 4 |  HASH JOIN   |   |  1 |  4 |  4 |00:00:00.01 |  6 | 898K| 898K| 554K (0)| 
| 5 |  TABLE ACCESS FULL| ASSIGNMENT |  1 |  4 |  4 |00:00:00.01 |  3 |  |  |   | 
| 6 |  TABLE ACCESS FULL| TYPE  |  1 |  4 |  4 |00:00:00.01 |  3 |  |  |   | 
------------------------------------------------------------------------------------------------------------------------- 

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

    4 - access("A"."TYPE_ID"="T"."TYPE_ID") 


28 rows selected. 

SQL> select /*+ gather_plan_statistics */ 
    2   a.id 
    3  , max(t.type_id) keep (dense_rank last order by t.create_date) max_create_date_type_id 
    4  , max(a.assign_id) keep (dense_rank last order by t.create_date) assign_id 
    5 from assignment a 
    6  , type t 
    7 where a.type_id = t.type_id 
    8 group by a.id 
    9/

ID MAX_CREATE_DATE_TYPE_ID ASSIGN_ID 
-- ----------------------- ---------- 
1x      3  664 
2x      4  514 

2 rows selected. 

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

PLAN_TABLE_OUTPUT 
------------------------------------------------------------------------------------------------------------------------- 

SQL_ID 156kpxgxmfjd3, child number 0 
------------------------------------- 
select /*+ gather_plan_statistics */  a.id  , max(t.type_id) 
keep (dense_rank last order by t.create_date) max_create_date_type_id 
    , max(a.assign_id) keep (dense_rank last order by t.create_date) 
assign_id from assignment a  , type t where a.type_id = 
t.type_id group by a.id 

Plan hash value: 3494156172 

----------------------------------------------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | 
----------------------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |   |  1 |  |  2 |00:00:00.01 |  6 |  |  |   | 
| 1 | SORT GROUP BY  |   |  1 |  2 |  2 |00:00:00.01 |  6 | 2048 | 2048 | 2048 (0)| 
|* 2 | HASH JOIN   |   |  1 |  4 |  4 |00:00:00.01 |  6 | 898K| 898K| 594K (0)| 
| 3 | TABLE ACCESS FULL| ASSIGNMENT |  1 |  4 |  4 |00:00:00.01 |  3 |  |  |   | 
| 4 | TABLE ACCESS FULL| TYPE  |  1 |  4 |  4 |00:00:00.01 |  3 |  |  |   | 
----------------------------------------------------------------------------------------------------------------------- 

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

    2 - access("A"."TYPE_ID"="T"."TYPE_ID") 


25 rows selected. 

Comme vous pouvez le voir, les deux sont la numérisation complète les tables et effectuer une jointure de hachage. La différence est après cette étape. La variante agrégée prend 4 lignes et les agrège en 2 lignes avec un SORT GROUP By. L'analytique consiste à trier d'abord le jeu de 4 lignes puis à appliquer un HASH UNIQUE pour réduire l'ensemble à 2 lignes.

Cordialement, Rob.

+0

Je crois que vous voulez les trier par t.create_date desc dans votre première requête, comme vous le faites dans votre test de performance. –

Questions connexes