如何重写此 Oracle 查询以使用高效的 CTE
how to rewrite this Oracle query to use efficient CTE
我有一个查询,我想通过使用 with
子句来改进它。我尝试了下面的一个变体,但我只能降低一点成本。我如何重写连接的主要部分只用 with 子句完成一次的查询,记住对于第二个子集我有这个额外的过滤器 AND WS.CODE ='S_WLM_WL_013'
?
如有任何想法,我们将不胜感激。
查询是
SELECT
CASE
WHEN ( SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID=
(SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID=:1
)
) =
(SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
AND WS.CODE ='S_WLM_WL_013'
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID=
(SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID=:1
)
)
THEN 'OK'
ELSE null END AS StatusAlert FROM DUAL
我试过这个
with t as ( SELECT MIN(IDENTIFICATOR_ID) as minval , message_id FROM EXIM1B.GER_CUSTOMER_ONBOARDING WHERE MESSAGE_ID=:1 group by message_id )
SELECT
CASE
WHEN ( SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO inner join t on t.message_id = gco.message_id
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID = t.minval
) =
(SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO inner join t on t.message_id = gco.message_id
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
AND WS.CODE ='S_WLM_WL_013'
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID = t.minval
)
THEN 'OK'
ELSE null END AS StatusAlert FROM DUAL
您可以减少在同一查询中计算过滤和未过滤状态的成本:
SELECT CASE WHEN COUNT(*) = SUM(CASE WHEN WS.CODE='S_WLM_WL_013' THEN 1 ELSE 0 END) THEN 'OK' ELSE NULL END AS StatusAlert
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH ON AH.AT_ID = GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS ON AH.WW_STATUS_CODE = WS.CODE
WHERE GCO.MESSAGE_ID = :1
AND GCO.IDENTIFICATOR_ID = (
SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID = :1
)
FROM DUAL
编辑
您可以进一步降低查询的成本,排除 WORKFLOW_STATUSES
table 上的 JOIN
并直接过滤 EXIM1B.ALERT_HEADER.WW_STATUS_CODE
SELECT CASE WHEN COUNT(*) = SUM(CASE WHEN /* WS.CODE */WW_STATUS_CODE='S_WLM_WL_013' THEN 1 ELSE 0 END) THEN 'OK' ELSE NULL END AS StatusAlert
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH ON AH.AT_ID = GCO.WLM_TRANSACTION_ID
/* EXIM1B.WORKFLOW_STATUSES NOT NEEDED */
/* INNER JOIN EXIM1B.WORKFLOW_STATUSES WS ON AH.WW_STATUS_CODE = WS.CODE */
WHERE GCO.MESSAGE_ID = :1
AND GCO.IDENTIFICATOR_ID = (
SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID = :1
)
FROM DUAL
你可以试试下面的,
WITH customer_onboarding
AS
(SELECT /*+ materialize */
gco.wlm_transaction_id
FROM exim1b.ger_customer_onboarding gco
WHERE gco.message_id = :1
AND gco.identificator_id = (SELECT MIN(identificator_id)
FROM exim1b.ger_customer_onboarding
WHERE message_id = :1)),
wrk_flw_not_filtered
AS
(SELECT /*+ materialize */
ws.code,count(*) over () as cnt_not_filtered
FROM customer_onboarding gco
JOIN exim1b.alert_header ah
ON ah.at_id = gco.wlm_transaction_id
JOIN exim1b.workflow_statuses ws
ON ah.ww_status_code = ws.code)
SELECT CASE
WHEN max(cnt_not_filtered) = count(*)
THEN 'OK'
END statusalert
FROM wrk_flw_not_filtered flt
WHERE flt.code = 'S_WLM_WL_013';
我有一个查询,我想通过使用 with
子句来改进它。我尝试了下面的一个变体,但我只能降低一点成本。我如何重写连接的主要部分只用 with 子句完成一次的查询,记住对于第二个子集我有这个额外的过滤器 AND WS.CODE ='S_WLM_WL_013'
?
如有任何想法,我们将不胜感激。
查询是
SELECT
CASE
WHEN ( SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID=
(SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID=:1
)
) =
(SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
AND WS.CODE ='S_WLM_WL_013'
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID=
(SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID=:1
)
)
THEN 'OK'
ELSE null END AS StatusAlert FROM DUAL
我试过这个
with t as ( SELECT MIN(IDENTIFICATOR_ID) as minval , message_id FROM EXIM1B.GER_CUSTOMER_ONBOARDING WHERE MESSAGE_ID=:1 group by message_id )
SELECT
CASE
WHEN ( SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO inner join t on t.message_id = gco.message_id
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID = t.minval
) =
(SELECT COUNT(*)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO inner join t on t.message_id = gco.message_id
INNER JOIN EXIM1B.ALERT_HEADER AH
ON AH.AT_ID=GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS
ON AH.WW_STATUS_CODE =WS.CODE
AND WS.CODE ='S_WLM_WL_013'
WHERE GCO.MESSAGE_ID =:1
AND GCO.IDENTIFICATOR_ID = t.minval
)
THEN 'OK'
ELSE null END AS StatusAlert FROM DUAL
您可以减少在同一查询中计算过滤和未过滤状态的成本:
SELECT CASE WHEN COUNT(*) = SUM(CASE WHEN WS.CODE='S_WLM_WL_013' THEN 1 ELSE 0 END) THEN 'OK' ELSE NULL END AS StatusAlert
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH ON AH.AT_ID = GCO.WLM_TRANSACTION_ID
INNER JOIN EXIM1B.WORKFLOW_STATUSES WS ON AH.WW_STATUS_CODE = WS.CODE
WHERE GCO.MESSAGE_ID = :1
AND GCO.IDENTIFICATOR_ID = (
SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID = :1
)
FROM DUAL
编辑
您可以进一步降低查询的成本,排除 WORKFLOW_STATUSES
table 上的 JOIN
并直接过滤 EXIM1B.ALERT_HEADER.WW_STATUS_CODE
SELECT CASE WHEN COUNT(*) = SUM(CASE WHEN /* WS.CODE */WW_STATUS_CODE='S_WLM_WL_013' THEN 1 ELSE 0 END) THEN 'OK' ELSE NULL END AS StatusAlert
FROM EXIM1B.GER_CUSTOMER_ONBOARDING GCO
INNER JOIN EXIM1B.ALERT_HEADER AH ON AH.AT_ID = GCO.WLM_TRANSACTION_ID
/* EXIM1B.WORKFLOW_STATUSES NOT NEEDED */
/* INNER JOIN EXIM1B.WORKFLOW_STATUSES WS ON AH.WW_STATUS_CODE = WS.CODE */
WHERE GCO.MESSAGE_ID = :1
AND GCO.IDENTIFICATOR_ID = (
SELECT MIN(IDENTIFICATOR_ID)
FROM EXIM1B.GER_CUSTOMER_ONBOARDING
WHERE MESSAGE_ID = :1
)
FROM DUAL
你可以试试下面的,
WITH customer_onboarding
AS
(SELECT /*+ materialize */
gco.wlm_transaction_id
FROM exim1b.ger_customer_onboarding gco
WHERE gco.message_id = :1
AND gco.identificator_id = (SELECT MIN(identificator_id)
FROM exim1b.ger_customer_onboarding
WHERE message_id = :1)),
wrk_flw_not_filtered
AS
(SELECT /*+ materialize */
ws.code,count(*) over () as cnt_not_filtered
FROM customer_onboarding gco
JOIN exim1b.alert_header ah
ON ah.at_id = gco.wlm_transaction_id
JOIN exim1b.workflow_statuses ws
ON ah.ww_status_code = ws.code)
SELECT CASE
WHEN max(cnt_not_filtered) = count(*)
THEN 'OK'
END statusalert
FROM wrk_flw_not_filtered flt
WHERE flt.code = 'S_WLM_WL_013';