1

产品

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'

当任一查询针对大型数据集运行时,性能都不是很好。我如何改进(甚至完全改变)上述查询以获得最佳性能?

4

4 回答 4

3

你试过使用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 表达式语法的问题。对于那个很抱歉。

于 2013-03-10T03:50:14.540 回答
1

尝试这个

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
于 2013-03-10T04:54:58.987 回答
1

除了以前的答案(我喜欢关于 INTERSECT anв MINUS 的答案)。

对于字段“product_status”的极少量可能值,普通索引(基于 B-Tree)无法正常工作。您需要在此字段上使用位图索引。 Oracle Bitmap Index Techniques CREATE INDEX in Oracle Docs - 搜索位图

于 2013-03-11T09:20:25.447 回答
1

使用MINUS和 INTERSECT可能会获得更好的速度,它们是 UNION 被忽视的表亲。

所有具有 PE​​NDING 和 PROCESSED 行的产品:

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

所有具有 PE​​NDING 行但没有 PROCESSED 行的产品:

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

将它们放在一起(并添加新/更新):

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.

于 2013-03-10T04:33:33.080 回答