如何在嵌套查询中传递where条件

时间:2016-02-10 10:03:48

标签: sql

运行以下脚本时遇到性能问题。执行此查询需要花费大量时间,超过1小时。

CREATE OR REPLACE VIEW VW_TEST AS
SELECT UNID AS UNIT_ID,AG_ID,STATION,EID,NUM_1 AS EVENT_NUMBER,
(TO_DATE(SUBSTR(DP,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS DP,
(TO_DATE(SUBSTR(ER,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS ER,
(TO_DATE(SUBSTR(AR,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AR,
(TO_DATE(SUBSTR(TR,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TR,
(TO_DATE(SUBSTR(TA,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TA,
(TO_DATE(SUBSTR(TP,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TP,
(TO_DATE(SUBSTR(PS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS PS,
(TO_DATE(SUBSTR(TG,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TG,
(TO_DATE(SUBSTR(AG,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AG,
(TO_DATE(SUBSTR(HB,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS HB,
(TO_DATE(SUBSTR(TO_LOC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TO_LOC,
(TO_DATE(SUBSTR(AO,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AO,
(TO_DATE(SUBSTR(TC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TC,
(TO_DATE(SUBSTR(AC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AC,
(TO_DATE(SUBSTR(AM,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AM,
(TO_DATE(SUBSTR(OS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS OS,
TRIP_NO
FROM (
SELECT * FROM (SELECT u.UNID, u.AG_ID, u.STATION ,u.EID, u.NUM_1, u.CDTS,u.UNIT_STATUS,ATH_TRIP_NO(u.RECOVERY_CDTS,u.EID,u.NUM_1,u.UNID) TRIP_NO 
FROM UN_HI u 
WHERE u.RECOVERY_CDTS IN(SELECT MAX(RECOVERY_CDTS) AS RECOVERY_CDTS FROM UN_HI GROUP BY UNID,AG_ID,STATION,EID,UNIT_STATUS,ATH_TRIP_NO(RECOVERY_CDTS,EID,NUM_1,UNID)) 
) 
PIVOT (MIN(CDTS) FOR (UNIT_STATUS) IN ('DP' DP,'ER' ER, 'AR' AR,'TR' TR,'TA' TA,'TP' TP,'PS' PS,'TG' TG,'AG' AG,'HB' HB,'TO' TO_LOC,'AO' AO,'TC' TC,'AC' AC,'AM' AM,'OS' OS)) ) t1
GROUP BY UNID,AG_ID,STATION,EID,NUM_1,DP,ER,AR,TR,TA,TP,PS,TG,AG,HB,TO_LOC,AO,TC,AC,AM,OS,TRIP_NO
ORDER BY EID,UNID,TRIP_NO

当我跑步时:

SELECT * FROM VW_TEST WHERE EID = 58100 

然后需要1个多小时。

但是当我在嵌套查询中传递where条件时,我会在5秒内得到结果。

SELECT UNID AS UNIT_ID,AG_ID,STATION,EID,NUM_1 AS EVENT_NUMBER,
(TO_DATE(SUBSTR(DP,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS DP,
(TO_DATE(SUBSTR(ER,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS ER,
(TO_DATE(SUBSTR(AR,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AR,
(TO_DATE(SUBSTR(TR,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TR,
(TO_DATE(SUBSTR(TA,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TA,
(TO_DATE(SUBSTR(TP,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TP,
(TO_DATE(SUBSTR(PS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS PS,
(TO_DATE(SUBSTR(TG,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TG,
(TO_DATE(SUBSTR(AG,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AG,
(TO_DATE(SUBSTR(HB,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS HB,
(TO_DATE(SUBSTR(TO_LOC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TO_LOC,
(TO_DATE(SUBSTR(AO,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AO,
(TO_DATE(SUBSTR(TC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TC,
(TO_DATE(SUBSTR(AC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AC,
(TO_DATE(SUBSTR(AM,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AM,
(TO_DATE(SUBSTR(OS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS OS,
TRIP_NO
FROM (
SELECT * FROM (SELECT u.UNID, u.AG_ID, u.STATION ,u.EID, u.NUM_1, u.CDTS,u.UNIT_STATUS,ATH_TRIP_NO(u.RECOVERY_CDTS,u.EID,u.NUM_1,u.UNID) TRIP_NO 
FROM UN_HI u 
WHERE u.EID = 58100 AND u.RECOVERY_CDTS IN(SELECT MAX(RECOVERY_CDTS) AS RECOVERY_CDTS FROM UN_HI WHERE EID = 58100 GROUP BY UNID,AG_ID,STATION,EID,UNIT_STATUS,ATH_TRIP_NO(RECOVERY_CDTS,EID,NUM_1,UNID)) 
) 
PIVOT (MIN(CDTS) FOR (UNIT_STATUS) IN ('DP' DP,'ER' ER, 'AR' AR,'TR' TR,'TA' TA,'TP' TP,'PS' PS,'TG' TG,'AG' AG,'HB' HB,'TO' TO_LOC,'AO' AO,'TC' TC,'AC' AC,'AM' AM,'OS' OS)) ) t1
GROUP BY UNID,AG_ID,STATION,EID,NUM_1,DP,ER,AR,TR,TA,TP,PS,TG,AG,HB,TO_LOC,AO,TC,AC,AM,OS,TRIP_NO
ORDER BY EID,UNID,TRIP_NO

但问题是我需要将它用作视图,并且不能在我的应用程序中使用这个大查询。任何建议都将受到高度赞赏。

2 个答案:

答案 0 :(得分:0)

如果使用的DBMS支持物化视图,则可以使用它们,以便在请求数据库时计算结果。例如,在类似Oracle的DBMS中,您可以使用类似:

的内容
CREATE MATERIALIZED VIEW VW_TEST 
REFRESH ON DEMAND
START WITH SYSDATE
NEXT SYSDATE + 1
AS
SELECT UNID AS UNIT_ID,AG_ID,STATION,EID,NUM_1 AS EVENT_NUMBER,
(TO_DATE(SUBSTR(DP,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS DP,
(TO_DATE(SUBSTR(ER,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS ER,
(TO_DATE(SUBSTR(AR,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AR,
(TO_DATE(SUBSTR(TR,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TR,
(TO_DATE(SUBSTR(TA,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TA,
(TO_DATE(SUBSTR(TP,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TP,
(TO_DATE(SUBSTR(PS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS PS,
(TO_DATE(SUBSTR(TG,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TG,
(TO_DATE(SUBSTR(AG,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AG,
(TO_DATE(SUBSTR(HB,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS HB,
(TO_DATE(SUBSTR(TO_LOC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TO_LOC,
(TO_DATE(SUBSTR(AO,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AO,
(TO_DATE(SUBSTR(TC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS TC,
(TO_DATE(SUBSTR(AC,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AC,
(TO_DATE(SUBSTR(AM,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS AM,
(TO_DATE(SUBSTR(OS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) AS OS,
TRIP_NO
FROM (
SELECT * FROM (SELECT u.UNID, u.AG_ID, u.STATION ,u.EID, u.NUM_1, u.CDTS,u.UNIT_STATUS,ATH_TRIP_NO(u.RECOVERY_CDTS,u.EID,u.NUM_1,u.UNID) TRIP_NO 
FROM UN_HI u 
WHERE u.RECOVERY_CDTS IN(SELECT MAX(RECOVERY_CDTS) AS RECOVERY_CDTS FROM UN_HI GROUP BY UNID,AG_ID,STATION,EID,UNIT_STATUS,ATH_TRIP_NO(RECOVERY_CDTS,EID,NUM_1,UNID)) 
) 
PIVOT (MIN(CDTS) FOR (UNIT_STATUS) IN ('DP' DP,'ER' ER, 'AR' AR,'TR' TR,'TA' TA,'TP' TP,'PS' PS,'TG' TG,'AG' AG,'HB' HB,'TO' TO_LOC,'AO' AO,'TC' TC,'AC' AC,'AM' AM,'OS' OS)) ) t1
GROUP BY UNID,AG_ID,STATION,EID,NUM_1,DP,ER,AR,TR,TA,TP,PS,TG,AG,HB,TO_LOC,AO,TC,AC,AM,OS,TRIP_NO
ORDER BY EID,UNID,TRIP_NO

这将每天刷新您的视图,您可以根据需要进行调整。

答案 1 :(得分:0)

作为第一个选项,我会尝试查看是否以允许优化器将EID上的条件推送到最嵌套的子查询的方式重写查询可以解决问题。下面的一个,其中EID用于半连接评估(IN子句),应该是好的。我无法保证它是正确的,因为我无法尝试,但我对此非常有信心。你应该测试它。

SELECT UNID AS UNIT_ID,AG_ID,STATION,EID,NUM_1 AS EVENT_NUMBER,
    DP, ER, AR, TR, TA, TP, PS, TG, AG, HB, TO_LOC, AO, TC, AC, AM, OS, 
    TRIP_NO
FROM (
        SELECT *
        FROM (
                SELECT u.UNID, u.AG_ID, u.STATION ,u.EID, u.NUM_1,
                    (TO_DATE(SUBSTR(u.CDTS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) as CDTS,
                    u.UNIT_STATUS,
                    ATH_TRIP_NO(u.RECOVERY_CDTS,u.EID,u.NUM_1,u.UNID) TRIP_NO 
                FROM UN_HI u
                WHERE (UNIT_STATUS) IN (
                        'DP','ER', 'AR','TR','TA','TP','PS','TG','AG','HB',
                        'TO_LOC','AO','TC','AC','AM','OS'
                    )
                    and (u.EID, u.RECOVERY_CDTS) IN(
                        SELECT u.EID,MAX(RECOVERY_CDTS) AS RECOVERY_CDTS 
                        FROM UN_HI 
                        GROUP BY u.EID,UNID,AG_ID,STATION,EID,UNIT_STATUS,ATH_TRIP_NO(RECOVERY_CDTS,EID,NUM_1,UNID)
                    )
            ) 
        PIVOT (
            MIN(CDTS) 
            FOR (UNIT_STATUS) IN (
                'DP' DP,'ER' ER, 'AR' AR,'TR' TR,'TA' TA,'TP' TP,'PS' PS,'TG' TG,'AG' AG,'HB' HB,
                'TO' TO_LOC,'AO' AO,'TC' TC,'AC' AC,'AM' AM,'OS' OS
            )
        )
    ) t1
GROUP BY UNID,AG_ID,STATION,EID,NUM_1,DP,ER,AR,TR,TA,TP,PS,TG,AG,HB,TO_LOC,AO,TC,AC,AM,OS,TRIP_NO
ORDER BY EID,UNID,TRIP_NO

然后我发现你使用"自我半连接"在RECOVERY_CDTS上共享最高值的那些中找到MIN(CDTS),可以使用LAST函数以更简单的方式找到它,因此您可以尝试这个也应该比前一个更快的查询而不是你原来的那个。

SELECT UNID AS UNIT_ID,AG_ID,STATION,EID,NUM_1 AS EVENT_NUMBER,
    DP, ER, AR, TR, TA, TP, PS, TG, AG, HB, TO_LOC, AO, TC, AC, AM, OS, 
    TRIP_NO
FROM (
        SELECT *
        FROM (
                SELECT u.UNID, u.AG_ID, u.STATION ,u.EID, u.NUM_1,
                    u.UNIT_STATUS,
                    ATH_TRIP_NO(u.RECOVERY_CDTS,u.EID,u.NUM_1,u.UNID) TRIP_NO,
                    min(TO_DATE(SUBSTR(u.CDTS,0,14),'YYYY/MM/dd HH24:MI:SS')+3/24) keep (dense_rank least order by RECOVERY_CDTS)as CDTS
                FROM UN_HI u
                where (UNIT_STATUS) IN (
                    'DP','ER', 'AR','TR','TA','TP','PS','TG','AG','HB',
                    'TO_LOC','AO','TC','AC','AM','OS'
                )
                GROUP BY UNID,AG_ID,STATION,EID,UNIT_STATUS,ATH_TRIP_NO(RECOVERY_CDTS,EID,NUM_1,UNID)
            ) 
        PIVOT (
            MIN(CDTS) 
            FOR (UNIT_STATUS) IN (
                'DP' DP,'ER' ER, 'AR' AR,'TR' TR,'TA' TA,'TP' TP,'PS' PS,'TG' TG,'AG' AG,'HB' HB,
                'TO' TO_LOC,'AO' AO,'TC' TC,'AC' AC,'AM' AM,'OS' OS
            )
        )
    ) t1
GROUP BY UNID,AG_ID,STATION,EID,NUM_1,DP,ER,AR,TR,TA,TP,PS,TG,AG,HB,TO_LOC,AO,TC,AC,AM,OS,TRIP_NO
ORDER BY EID,UNID,TRIP_NO