在LINUX上使用Oracle 10gR2,我正在尝试调整以下查询 我很确定摆脱相关子查询和可能使用某些分析函数可能是最佳方法,但我只是没有得到它 - 特别是在MAX上选择的嵌套相关子查询( TABLE_2.NOTE_DATE)。任何帮助将非常感激。感谢。
EXPLAIN PLAN FOR
SELECT TABLE_4.INCIDENT_TYPE,
TABLE_4.POC_CONTACT,
(SELECT TABLE_2.NOTE_DATE
|| ' '
|| TABLE_1.USER_FIRST_NAME
|| ' '
|| TABLE_1.USER_LAST_NAME
|| ' : '
|| TABLE_2.OTHER_HELP_NOTES
FROM TABLE_1,
TABLE_2
WHERE TABLE_2.USER_ID = TABLE_1.USER_ID
AND TABLE_2.REC_ID = TABLE_4.REC_ID
AND TABLE_2.NOTE_DATE = (SELECT MAX(TABLE_2.NOTE_DATE)
FROM TABLE_2
WHERE TABLE_2.REC_ID = TABLE_4.REC_ID
AND TABLE_2.NOTE_DATE <=
TABLE_4.REPORT_DATE))
AS SUM_OF_SHORTAGE,
(SELECT TABLE_3.NOTE_DATE
|| ' '
|| TABLE_1.USER_FIRST_NAME
|| ' '
|| TABLE_1.USER_LAST_NAME
|| ' : '
|| TABLE_3.HELP_NOTES
FROM TABLE_1,
TABLE_3
WHERE TABLE_3.USER_ID = TABLE_1.USER_ID
AND TABLE_3.REC_ID = TABLE_4.REC_ID
AND TABLE_3.NOTE_DATE = (SELECT MAX(TABLE_3.NOTE_DATE)
FROM TABLE_3
WHERE TABLE_3.REC_ID = TABLE_4.REC_ID
AND TABLE_3.NOTE_DATE <=
TABLE_4.REPORT_DATE)) AS HELP_NOTES,
TABLE_4.REPORT_NUM
FROM TABLE_4
WHERE TABLE_4.SITE_ID = '1';
@C:\ORACLE\PRODUCT\11.2.0\CLIENT_1\RDBMS\ADMIN\UTLXPLS.SQL;
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PLAN HASH VALUE: 4036328474
------------------------------------------------------------------------------------------------------------
| ID | OPERATION | NAME | ROWS | BYTES | COST (%CPU)| TIME |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 13009 | 2286K| 449 (2)| 00:00:06 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS | | 3 | 612 | 8 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| TABLE_2 | 3 | 552 | 5 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | IX_TABLE_2_REC_ID | 3 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| TABLE_1 | 1 | 20 | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | TABLE_1_PK | 1 | | 0 (0)| 00:00:01 |
| 7 | SORT AGGREGATE | | 1 | 13 | | |
|* 8 | TABLE ACCESS BY INDEX ROWID| TABLE_2 | 1 | 13 | 5 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | IX_TABLE_2_REC_ID | 3 | | 1 (0)| 00:00:01 |
|* 10 | FILTER | | | | | |
|* 11 | HASH JOIN | | 17 | 4063 | 482 (2)| 00:00:06 |
|* 12 | TABLE ACCESS FULL | TABLE_3 | 17 | 3723 | 474 (2)| 00:00:06 |
| 13 | TABLE ACCESS FULL | TABLE_1 | 1504 | 30080 | 8 (0)| 00:00:01 |
| 14 | SORT AGGREGATE | | 1 | 13 | | |
|* 15 | TABLE ACCESS FULL | TABLE_3 | 1 | 13 | 474 (2)| 00:00:06 |
|* 16 | TABLE ACCESS FULL | TABLE_4 | 13009 | 2286K| 449 (2)| 00:00:06 |
------------------------------------------------------------------------------------------------------------
PREDICATE INFORMATION (IDENTIFIED BY OPERATION ID):
---------------------------------------------------
1 - FILTER("TABLE_2"."NOTE_DATE"= (SELECT /*+ */ MAX("TABLE_2"."NOTE_DATE")
FROM "TABLE_2" "TABLE_2" WHERE "TABLE_2"."REC_ID"=:B1 AND
"TABLE_2"."NOTE_DATE"<=:B2))
4 - ACCESS("TABLE_2"."REC_ID"=:B1)
6 - ACCESS("TABLE_2"."USER_ID"="TABLE_1"."USER_ID")
8 - FILTER("TABLE_2"."NOTE_DATE"<=:B1)
9 - ACCESS("TABLE_2"."REC_ID"=:B1)
10 - FILTER("TABLE_3"."NOTE_DATE"= (SELECT /*+ */
MAX("TABLE_3"."NOTE_DATE") FROM "TABLE_3" "TABLE_3" WHERE
"TABLE_3"."REC_ID"=:B1 AND "TABLE_3"."NOTE_DATE"<=:B2))
11 - ACCESS("TABLE_3"."USER_ID"="TABLE_1"."USER_ID")
12 - FILTER("TABLE_3"."REC_ID"=:B1)
15 - FILTER("TABLE_3"."REC_ID"=:B1 AND "TABLE_3"."NOTE_DATE"<=:B2)
16 - FILTER("TABLE_4"."SITE_ID"=1)
41 ROWS SELECTED
打破这个问题 - 关键问题似乎如下:
select REC_ID, TO_CHAR(REPORT_DATE,'DD-MON-YY HH:MI:SS') REPORT_DATE,
(SELECT MAX(TABLE_2.note_date) as MAX_DATE
FROM TABLE_2
where TABLE_2.REC_ID = TABLE_1.REC_ID
and TABLE_2.NOTE_DATE <= TABLE_1.REPORT_DATE
) NOTES_MAX_DATE
from TABLE_1 where REC_ID = 121 order by TO_DATE(REPORT_DATE,'DD-MON-YY HH:MI:SS');
哪个应返回以下内容:
REC_ID REPORT_DATE NOTES_MAX_DATE
---------------------- ------------------ -------------------------
121 17-APR-10 12:30:00
121 24-APR-10 12:30:00
121 01-MAY-10 12:30:00
121 08-MAY-10 12:30:00
121 15-MAY-10 12:30:00 12-MAY-10
121 22-MAY-10 12:30:01 17-MAY-10
121 29-MAY-10 12:30:01 25-MAY-10
121 05-JUN-10 12:30:00 25-MAY-10
8 rows selected
输出必须与上述相同。我尝试按如下方式创建联接:
SELECT TABLE_1.REC_ID, TO_CHAR(TABLE_1.REPORT_DATE,'DD-MON-YY HH:MI:SS') REPORT_DATE, MAX(TABLE_2.NOTE_DATE) AS NOTES_MAX_DATE
FROM TABLE_2,
TABLE_1
where TABLE_2.REC_ID = TABLE_1.REC_ID
AND TABLE_2.NOTE_DATE <= TABLE_1.REPORT_DATE
and ( TABLE_1.SITE_ID = '1' )
and TABLE_1.REC_ID = 121
group by TABLE_1.REC_ID, TABLE_1.REPORT_DATE
order by TO_DATE(REPORT_DATE,'DD-MON-YY HH:MI:SS');
但是这会产生:
REC_ID REPORT_DATE NOTES_MAX_DATE
---------------------- ------------------ -------------------------
121 15-MAY-10 12:30:00 12-MAY-10
121 22-MAY-10 12:30:01 17-MAY-10
121 29-MAY-10 12:30:01 25-MAY-10
121 05-JUN-10 12:30:00 25-MAY-10
所以我真的很难过。有任何想法吗? - 谢谢。
答案 0 :(得分:2)
以下版本仅获取应移除相关的子查询。它仍然使用子查询,但是,由于它们位于max
一次,而FROM
子句而不是SELECT
子句中,因此数据库应该更好地解决它们。也可以删除这些子查询,但这种方式更具可读性。此版本还使用SQL-99语法进行连接,这通常被认为是可取的。
SELECT table_4.incident_type,
table_4.poc_contact,
t2.sum_of_shortage,
t3.help_notes,
table_4.report_num
FROM table_4
LEFT JOIN (SELECT table_2.rec_id,
table_2.note_date
|| ' '
|| table_1.user_first_name
|| ' '
|| table_1.user_last_name
|| ' : '
|| table_2.other_help_notes
AS sum_of_shortage
FROM table_1
JOIN table_2
ON table_2.user_id = table_1.user_id
WHERE table_2.note_date =
(SELECT MAX(table_2.note_date) AS max_date
FROM table_2
WHERE table_2.rec_id = table_4.rec_id
AND table_2.note_date <= table_4.report_date)) t2
ON t2.rec_id = table_4.rec_id
LEFT JOIN (SELECT table_3.rec_id,
table_3.note_date
|| ' '
|| table_1.user_first_name
|| ' '
|| table_1.user_last_name
|| ' : '
|| table_3.other_help_notes
AS help_notes
FROM table_1
JOIN table_3
ON table_3.user_id = table_1.user_id
WHERE table_2.note_date =
(SELECT MAX(table_3.note_date) AS max_date
FROM table_3
WHERE table_3.rec_id = table_4.rec_id
AND table_3.note_date <= table_4.report_date)) t3
ON t3.rec_id = table_4.rec_id
WHERE table_4.site_id = '1';
@shawno:你没错,with
条款有缺陷,因为我误读了你的初始查询。以上是更正后的版本。由于max
值特定于每一行,因此您用于获取这些值的方法可能效率最高。您优化此选项的最佳选择似乎只是将子查询从select
子句移动到from
子句。
此外,这是一个未经测试的解决方案,因为我既没有您的表结构也没有您的数据。我能做的最好的事情就是验证语法是否有效。