2009-07-22 10 views
0

Ich habe die folgenden TabellenOracle Abfrageoptimierung

Master-Tabelle

id  
---- 
1x 
2x  

....

Zuordnungstabelle

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

Typ Tabelle

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

Was ich für die Abfrage ausgeben muß, ist so etwas wie diese

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

Im Moment habe ich so etwas wie dies tue, um die Ergebnisse zu erwerben, aber ich bin sicher, es ist ein viel besserer Weg, dies zu tun .

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 

Vielen Dank für jede Hilfe

Antwort

4

Keine temporäre Tabelle erforderlich.

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

Dank Jeffery. Ich habe noch nie von den First_value- und over-Befehlen gehört. – AlteredConcept

+1

Nachschlagen "Oracle analytische Funktionen" - sie sind sehr mächtig :) empfohlen zu lesen: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions001.htm#i81407 –

+0

korrigiert, nach Lesen Vincents Antwort. –

2

Wenn Sie Oracle9i Release 2 oder höher verwenden, können Sie die WITH-Klausel verwenden. Anstatt eine temporäre Tabelle Q1 zu erstellen und dann Q2 auszuführen, könnten Sie nur eine Anweisung haben.

Nicht nur die Syntax wird kürzer, aber dies kann auch die Abfragegeschwindigkeit verbessern.

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

Ihre Abfrage würde so etwas geworden:

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

Sie können Analytics verwenden, um das Ergebnis in einer Abfrage zu erhalten:

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

Mit Analysen und dann die DISTINCT-Operator Anwendung nicht der richtige Weg ist, zu gehen, wenn Sie aggregieren müssen.

Hier ist eine einfachere und leistungsfähigere Version nur Aggregate mit:

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. 

Und hier ist ein Test zu beweisen, es ist mehr 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. 

Wie Sie sehen können, die beide vollständige Abtastung sind die Tabellen und führen einen Hash-Join durch. Der Unterschied ist nach diesem Schritt. Die Aggregatvariante nimmt 4 Zeilen und aggregiert sie zu 2 Zeilen mit einer SORT GROUP By. Der analytische sortiert zuerst den 4-Zeilen-Satz zweimal und wendet dann einen HASH UNIQUE an, um den Satz auf 2 Zeilen zu reduzieren.

Grüße, Rob.

+0

Ich glaube, Sie möchten sie von t.create_date desc in Ihrer ersten Abfrage bestellt, wie Sie in Ihrem Leistungstest tun. –