我的下面的查询花了太长时间:
{SELECT /*+ PARALLEL(5) */
EXTER.ACE_IT_REGION_ID ,
EXTER.ACE_IT_LOCATION_CODE,
EXTER.ACE_IT_ORD_NUM,
EXTER.TOTAL_ITEM_PRICE_PER_ORDER,
EXTER.TOTAL_ACE_PAYD_AMOUNT,
EXTER.ACE_ORD_COMPLETION_TIME AS DATEOFDATA
FROM
(SELECT /*+ use_hash(TAB1,TAB2) +*/
DISTINCT
TAB1.ACE_IT_REGION_ID ,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM,
TAB1.TOTAL_ITEM_PRICE_PER_ORDER,
TAB2.TOTAL_ACE_PAYD_AMOUNT,
TAB1.ACE_ORD_COMPLETION_TIME
FROM
(SELECT AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.SUM_PRICE_PLUS_TAX,
AAA.TOTAL_DISCOUNT,
(AAA.SUM_PRICE_PLUS_TAX-AAA.TOTAL_DISCOUNT) AS TOTAL_ITEM_PRICE_PER_ORDER,
TRUNC(AAA.ACE_ORD_COMPLETION_TIME)
FROM (SELECT B.ACE_IT_REGION_ID AS ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE AS ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM AS ACE_IT_ORD_NUM,
(SUM(B.ACE_IT_ITEM_PRICE + B.ACE_IT_TAX_AMT)*B.ACE_IT_QTY) AS SUM_PRICE_PLUS_TAX,
SUM(B.ACE_IT_DISC_AMT+B.ACE_IT_AUTO_DISC_AMT) AS TOTAL_DISCOUNT,
TRUNC(A.ACE_ORD_COMPLETION_TIME ) AS ACE_ORD_COMPLETION_TIME
FROM POSDB.ACE_ORDERS A, POSDB.ACE_ITEM_TRAN B
WHERE A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
AND A.ACE_ORD_REGION_ID = B.ACE_IT_REGION_ID
AND A.ACE_ORD_LOCATION_CODE = B.ACE_IT_LOCATION_CODE
AND A.ACE_ORD_NUM = B.ACE_IT_ORD_NUM
AND A.ACE_ORD_TYPE = 'IS'
AND (A.ACE_ORD_STATUS = 'CR'
OR A.ACE_ORD_STATUS IS NULL
OR A.ACE_ORD_STATUS LIKE ' %'
OR A.ACE_ORD_STATUS LIKE '% ')
AND (B.ACE_IT_VOID_IND <> 'V' OR B.ACE_IT_VOID_IND IS NULL )
GROUP BY B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
A.ACE_ORD_COMPLETION_TIME) AAA
ORDER BY AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.ACE_ORD_COMPLETION_TIME) TAB1,
(SELECT ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM,
SUM(ACE_PAYD_AMOUNT) TOTAL_ACE_PAYD_AMOUNT
FROM POSDB.ACE_PAYMENT_DTL
WHERE ACE_PAYD_POSTING_TIMESTAMP BETWEEN TRUNC(SYSDATE-1) AND TRUNC(SYSDATE)
AND (ACE_PAYD_STATUS <> 'V' OR ACE_PAYD_STATUS IS NULL )
GROUP BY
ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM) TAB2
WHERE TAB1.ACE_IT_REGION_ID = TAB2.ACE_PAYD_REGION_ID
AND TAB1.ACE_IT_LOCATION_CODE = TAB2.ACE_PAYD_LOCATION_CODE
AND TAB1.ACE_IT_ORD_NUM = TAB2.ACE_PAYD_ORD_NUM
ORDER BY
TAB1.ACE_IT_REGION_ID ,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM ) EXTER
WHERE (EXTER.TOTAL_ITEM_PRICE_PER_ORDER = EXTER.TOTAL_ACE_PAYD_AMOUNT)
AND EXTER.ACE_ORD_COMPLETION_TIME IS NOT NULL;}
请给我任何建议。我已经使用了提示,但仍然不确定为什么花了这么多时间。 所有的桌子都很大,每个都有300,000,000个。
在tab3临时表中加入表格之前需要花费5分钟......但现在即使在20-25分钟之后它也不会返回记录。
答案 0 :(得分:1)
略微清理以确保每个下一级子集的可读性。还删除了冗余外部查询,并将其添加到内部的WHERE子句中。应该是相同的结果
SELECT DISTINCT *
FROM
( SELECT
AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.SUM_PRICE_PLUS_TAX,
AAA.TOTAL_DISCOUNT,
AAA.SUM_PRICE_PLUS_TAX - AAA.TOTAL_DISCOUNT AS TOTAL_ITEM_PRICE_PER_ORDER,
TRUNC(AAA.ACE_ORD_COMPLETION_TIME) AS DATEOFDATA
FROM
( SELECT
B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
( SUM( B.ACE_IT_ITEM_PRICE + B.ACE_IT_TAX_AMT)
* B.ACE_IT_QTY ) AS SUM_PRICE_PLUS_TAX,
SUM( B.ACE_IT_DISC_AMT + B.ACE_IT_AUTO_DISC_AMT) AS TOTAL_DISCOUNT,
TRUNC( A.ACE_ORD_COMPLETION_TIME ) AS ACE_ORD_COMPLETION_TIME
FROM
POSDB.ACE_ORDERS A,
POSDB.ACE_ITEM_TRAN B
WHERE
A.ACE_ORD_TYPE = 'IS'
AND A.ACE_ORD_REGION_ID = B.ACE_IT_REGION_ID
AND A.ACE_ORD_LOCATION_CODE = B.ACE_IT_LOCATION_CODE
AND A.ACE_ORD_NUM = B.ACE_IT_ORD_NUM
AND A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
AND ( A.ACE_ORD_STATUS = 'CR'
OR A.ACE_ORD_STATUS IS NULL
OR A.ACE_ORD_STATUS LIKE ' %'
OR A.ACE_ORD_STATUS LIKE '% ')
AND ( B.ACE_IT_VOID_IND <> 'V'
OR B.ACE_IT_VOID_IND IS NULL )
GROUP BY
B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
A.ACE_ORD_COMPLETION_TIME ) AAA
ORDER BY
AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.ACE_ORD_COMPLETION_TIME) TAB1,
( SELECT
APD.ACE_PAYD_REGION_ID,
APD.ACE_PAYD_LOCATION_CODE,
APD.ACE_PAYD_ORD_NUM,
SUM(APD.ACE_PAYD_AMOUNT) TOTAL_ACE_PAYD_AMOUNT
FROM
POSDB.ACE_PAYMENT_DTL APD
WHERE
APD.ACE_PAYD_POSTING_TIMESTAMP
BETWEEN TRUNC(SYSDATE-1) AND TRUNC(SYSDATE)
AND ( APD.ACE_PAYD_STATUS <> 'V'
OR APD.ACE_PAYD_STATUS IS NULL )
GROUP BY
APD.ACE_PAYD_REGION_ID,
APD.ACE_PAYD_LOCATION_CODE,
APD.ACE_PAYD_ORD_NUM ) TAB2
WHERE
TAB1.ACE_IT_REGION_ID = TAB2.ACE_PAYD_REGION_ID
AND TAB1.ACE_IT_LOCATION_CODE = TAB2.ACE_PAYD_LOCATION_CODE
AND TAB1.ACE_IT_ORD_NUM = TAB2.ACE_PAYD_ORD_NUM
AND TAB1.TOTAL_ITEM_PRICE_PER_ORDER = TAB2.TOTAL_ACE_PAYD_AMOUNT,
AND TAB1.ACE_ORD_COMPLETION_TIME IS NOT NULL
ORDER BY
TAB1.ACE_IT_REGION_ID,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM ) EX
为了帮助优化,我可以推荐以下索引,因为你没有这样的索引 显示在您的结构/索引的帖子中...付款明细索引实际上是一个覆盖索引,意思是具有where,group by和sum单个字段的元素。这样就不必转到原始表页面来进行查询。它可以直接从索引字段中执行,每个字段都应该针对连接进行优化以及在哪里进行批判。
table index on..
ACE_ORDERS ( ACE_ORD_TYPE, ACE_ORD_COMPLETION_TIME, ACE_ORD_REGION_ID, ACE_ORD_LOCATION_CODE, ACE_ORD_NUM, ACE_ORD_STATUS )
ACE_ITEM_TRAN ( ACE_IT_REGION_ID, ACE_IT_LOCATION_CODE, ACE_IT_ORD_NUM, ACE_IT_VOID_IND )
ACE_PAYMENT_DTL ( ACE_PAYD_POSTING_TIMESTAMP, ACE_PAYD_REGION_ID, ACE_PAYD_LOCATION_CODE, ACE_PAYD_ORD_NUM, ACE_PAYD_STATUS, ACE_PAYD_AMOUNT )
答案 1 :(得分:0)
您需要使用JOINS重写查询,并确保正在连接的字段具有索引。
您修改后的查询应采用以下格式:
SELECT tab1.fld1, tab.fld2
FROM tab1
JOIN tab2 ON (tab2.ID = tab1.ID AND tab2.fld3 = 'xxx')
JOIN tab3 ON (tab3.ID2 = tab2.ID2)
WHERE tab1.fld4 = 'aaa'
and tab3.fld5 > 100
这将允许SQL优化器完成其工作。
答案 2 :(得分:0)
SELECT /*+ PARALLEL(5) */
EXTER.ACE_IT_REGION_ID ,
EXTER.ACE_IT_LOCATION_CODE,
EXTER.ACE_IT_ORD_NUM,
EXTER.TOTAL_ITEM_PRICE_PER_ORDER,
EXTER.TOTAL_ACE_PAYD_AMOUNT,
EXTER.ACE_ORD_COMPLETION_TIME AS DATEOFDATA
FROM
(SELECT /*+ use_hash(TAB1,TAB2) +*/
DISTINCT
TAB1.ACE_IT_REGION_ID ,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM,
TAB1.TOTAL_ITEM_PRICE_PER_ORDER,
TAB2.TOTAL_ACE_PAYD_AMOUNT,
TAB1.ACE_ORD_COMPLETION_TIME
FROM
(SELECT AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.SUM_PRICE_PLUS_TAX,
AAA.TOTAL_DISCOUNT,
-- There is no necessary that you write another subquery to finish below sql, you can do it in AAA
(AAA.SUM_PRICE_PLUS_TAX-AAA.TOTAL_DISCOUNT) AS TOTAL_ITEM_PRICE_PER_ORDER,
TRUNC(AAA.ACE_ORD_COMPLETION_TIME)
FROM (SELECT B.ACE_IT_REGION_ID AS ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE AS ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM AS ACE_IT_ORD_NUM,
(SUM(B.ACE_IT_ITEM_PRICE + B.ACE_IT_TAX_AMT)*B.ACE_IT_QTY) AS SUM_PRICE_PLUS_TAX,
SUM(B.ACE_IT_DISC_AMT+B.ACE_IT_AUTO_DISC_AMT) AS TOTAL_DISCOUNT,
TRUNC(A.ACE_ORD_COMPLETION_TIME ) AS ACE_ORD_COMPLETION_TIME
FROM POSDB.ACE_ORDERS A, POSDB.ACE_ITEM_TRAN B
WHERE
A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
-- you can remove it replace by trunc(A.ACE_ORD_COMPLETION_TIME) = TRUNC(SYSDATE -1) if there is no index on this column.
-- A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
-- AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
AND A.ACE_ORD_REGION_ID = B.ACE_IT_REGION_ID
AND A.ACE_ORD_LOCATION_CODE = B.ACE_IT_LOCATION_CODE
AND A.ACE_ORD_NUM = B.ACE_IT_ORD_NUM
AND A.ACE_ORD_TYPE = 'IS'
AND (A.ACE_ORD_STATUS = 'CR'
OR A.ACE_ORD_STATUS IS NULL
-- I think it better to replace blow by OR INSTR(ACE_ORD_STATUS,' ') > -1
-- OR A.ACE_ORD_STATUS LIKE ' %'
-- OR A.ACE_ORD_STATUS LIKE '% '
)
AND (B.ACE_IT_VOID_IND <> 'V' OR B.ACE_IT_VOID_IND IS NULL )
GROUP BY B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
A.ACE_ORD_COMPLETION_TIME
) AAA
-- remove order by clause in subquery, it's useless.
-- ORDER BY AAA.ACE_IT_REGION_ID,
-- AAA.ACE_IT_LOCATION_CODE,
-- AAA.ACE_IT_ORD_NUM,
-- AAA.ACE_ORD_COMPLETION_TIME
) TAB1,
(SELECT ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM,
SUM(ACE_PAYD_AMOUNT) TOTAL_ACE_PAYD_AMOUNT
FROM POSDB.ACE_PAYMENT_DTL
WHERE ACE_PAYD_POSTING_TIMESTAMP BETWEEN TRUNC(SYSDATE-1) AND TRUNC(SYSDATE)
AND (ACE_PAYD_STATUS <> 'V' OR ACE_PAYD_STATUS IS NULL )
GROUP BY
ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM) TAB2
WHERE TAB1.ACE_IT_REGION_ID = TAB2.ACE_PAYD_REGION_ID
AND TAB1.ACE_IT_LOCATION_CODE = TAB2.ACE_PAYD_LOCATION_CODE
AND TAB1.ACE_IT_ORD_NUM = TAB2.ACE_PAYD_ORD_NUM
-- remove order by clause in subquery, it's useless.
--ORDER BY
-- TAB1.ACE_IT_REGION_ID ,
-- TAB1.ACE_IT_LOCATION_CODE,
-- TAB1.ACE_IT_ORD_NUM
) EXTER
WHERE (EXTER.TOTAL_ITEM_PRICE_PER_ORDER = EXTER.TOTAL_ACE_PAYD_AMOUNT)
AND EXTER.ACE_ORD_COMPLETION_TIME IS NOT NULL;
-- Fix it like this for tempory, please supply explain plan for further.
-- There are so many columns like "ACE_PAYD_STATUS is not null", as you know, index could not contain null value.
-- But I think you can create an similarly index like "create index *** on ACE_PAYMENT_DTL(ACE_PAYD_STATUS,0)" to keep null values in your index.