[英]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'
當對大數據集運行兩個查詢時,性能都不是很好。 我如何才能改善(甚至完全改變)上述查詢以獲得最佳性能?
使用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.