2009-07-22 182 views
0

我有以下表甲骨文查询优化

主表

id  
---- 
1x 
2x  

....

分配表

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

类型表

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

我需要查询,以输出,怎么是这样的

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

我现在正在做这样的事情来获得结果,但我敢肯定有一个更好的方法来做到这一点。

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 

感谢所有帮助

回答

4

没有临时表需要。

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

谢谢jeffery。 我从来没有听说过first_value和over命令。 – AlteredConcept 2009-07-22 14:43:46

+1

查看“Oracle分析功能” - 它们功能非常强大:)推荐阅读:http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions001.htm#i81407 – 2009-07-22 14:45:47

2

如果使用Oracle9i第2版或更高版本,可以使用WITH子句。然后,不必创建临时表Q1然后运行Q2,而只需要一条语句。

不仅语法会更短,而且还可以提高查询速度。

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

你的查询将成为类似:

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

您可以使用分析得到的结果在一个查询:

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

使用分析,然后应用DISTINCT运算符是不是要走的路,当你需要聚集。

这里是一个更简单和更高性能的版本,只用骨料:

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. 

,这里是一个测试,以证明它更高性能:

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. 

正如你所看到的,两者都是全扫描表并执行散列连接。区别在于这一步之后。聚合变体需要4行,并使用SORT GROUP By将它们聚合为2行。分析人员首先对4行集合进行两次排序,然后应用HASH UNIQUE将该集合减少为2行。

Regards, Rob。