簡體   English   中英

我如何改善此查詢以在Oracle上獲得更好的性能

[英]How can i improve this query for better performance on Oracle

產品展示

product_id  product_serial_number   product_status
1           X123                    PENDING
1           X123                    PROCESSED
2           X345                    PENDING
3           X678                    PENDING
4           Y890                    PENDING
4           Y890                    PROCESSED

上表顯示了產品的狀態及其歷史記錄。 我需要生成一個報告,其輸出如下所示:

product_id  status
1           UPDATE
2           NEW
3           NEW
4           UPDATE

即,如果先前已經處理過某個產品(例如,產品1和4),則其狀態為UPDATE,否則其狀態為NEW。

我想出了這個查詢,但是我對它的性能不滿意:

select product_id, 'UPDATE'
from products p1
where product_id in (select product_id from products p2 where p2.product_status='PROCESSED' and p2.product_status='ARCHIVED')
Union
select product_id, 'NEW'
from products p1
where product_id not in (select product_id from products p2 where p2.product_status='PROCESSED' and p2.product_status='ARCHIVED')

另一種可行的方法是將表連接到自身:

select p1.product_id, decode(p2.product_id, null, 'NEW','UPDATE')
from products p1, products p2
where p1.product_id=p2.product_id(+)
and p1.product_serial_number=p2.serial_number(+)
and p2.product_status(+) = 'PROCESSED'

當對大數據集運行兩個查詢時,性能都不是很好。 我如何才能改善(甚至完全改變)上述查詢以獲得最佳性能?

您是否嘗試過使用GROUP BY

SELECT product_id, (CASE WHEN COUNT(*) = 1 THEN 'NEW' ELSE 'UPDATED' END) status
FROM products
WHERE product_status <> 'ARCHIVED'
GROUP BY product_id

查看其他GROUP BY 聚合函數

編輯

解決了Case表達式語法的問題。 對於那個很抱歉。

使用MINUS和INTERSECT 可能會獲得更好的速度,這是UNION的近親。

具有待處理和已處理行的所有產品:

SELECT product_id FROM Products WHERE product_status = 'PENDING'
INTERSECT SELECT product_id FROM Products WHERE product_status = 'PROCESSED'

所有具有PENDING行但沒有PROCESSED行的產品:

SELECT product_id FROM Products WHERE product_status = 'PENDING'
MINUS SELECT product_id FROM Products WHERE product_status = 'PROCESSED'

將它們放在一起(並添加NEW / UPDATE):

SELECT product_id, 'NEW' FROM (
   SELECT product_id FROM Products WHERE product_status = 'PENDING'
   MINUS SELECT product_id FROM Products WHERE product_status = 'PROCESSED')
UNION
SELECT product_id, 'UPDATE' FROM (
  SELECT product_id FROM Products WHERE product_status = 'PENDING'
  INTERSECT SELECT product_id FROM Products WHERE product_status = 'PROCESSED')

對於大表,您將涉及至少2/3的行,因此查詢永遠不會超級快。

如果計划大量運行此查詢,則可能還需要考慮product_status上的索引。

嘗試這個

with CTE as
(
   select product_id, decode(product_status,'PROCESSED','UPDATE','NEW') status,
   row_number() over (partition by product_id
   order by decode(product_status,'PROCESSED','UPDATE','NEW') desc) rnum
   from products p1
)
select * from cte where rnum = 1

除了以前的答案(我喜歡關於INTERSECT和MINUS的答案)。

對於字段'product_status'的很小可能值,普通索引(基於B-Tree)不能很好地工作。 您需要在此字段上使用位圖索引。 Oracle位圖索引技術 在Oracle Docs中創建索引-搜索位圖

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM