我有两个表 - '订单'和'订购商品'。
这两个表之间的连接条件是订单号。
在我的目标表中,我需要订单和标志。标志应该告诉我们,如果有一组预定义的产品已作为该订单的一部分订购,则应将其设置为“是”。
,例如,假设一个订单' ORD-01'在订单项目表中包含三个产品 - '移动',' PC'和' Tablet',然后我的结果表应包含订单号为ORD-01,标记为'是'。 以同样的方式,如果订购' ORD-02'仅包含两个产品' Mobile' '平板电脑'然后生成的表应该包含' ORD-02'和国旗'否'。 同样,如果订购' ORD-03'包含三种不同的产品' 笔记本',' PC' '平板电脑'然后生成的表应包含' ORD-03'和国旗'否'。
根据我的理解,我写了下面的查询 -
SELECT order_number,(SELECT CASE WHEN COUNT(DISTINCT product_name)>=3
THEN 'Yes' ELSE 'No' END Prod_Flag
FROM order_item b
WHERE a.order_number=b.order_number
AND b.product_name IN ('Mobile','PC','Tablet'))
FROM order a
WHERE order_date>last_run_date;
但这需要花费太多时间,因为订单项是一个非常大的表(> 10亿行)。但是,我需要基于订单表中订单日期的增量数据。即使两个表中都有订单编号索引,也需要时间。
答案 0 :(得分:0)
通常,您的查询是正确的。据我所知,你希望提高它的速度。如果是这样,有几种方法可以尝试。
您可以考虑将这些表放入索引群集中。它将存储物理连接的数据,因此查询将需要较少的物理读取。
对于此查询,服务器应扫描两个表:一个用于适当的日期(eigther全表扫描或索引扫描),另一个用于产品,并通过rowid读取ORDER_NUMBER来加入结果。反正它不是很快。最简单的方法是为ORDERs添加(ORDER_DATE,ORDER_NUMBER)索引,为ORDER_ITEMs添加(ORDER_NUMBER,PRODUCT_NAME)索引;它只允许使用索引。
也许适合制作快速可刷新的物化视图,例如
create materialized view as
select
a.order_date,
a.order_number,
sum(case when b.product_name = 'Mobile' then 1 else 0 end) cnt_mobiles,
sum(case when b.product_name = 'PC' then 1 else 0 end) cnt_pcs,
sum(case when b.product_name = 'Tablet' then 1 else 0 end) cnt_tablets
from
order a, order_item b
where
a.order_number = b.order_number
group by
a.order_number, a.order_date
如果不可能使这种快速刷新,你可以使用触发器手动做同样的事情。无论如何,在这种情况下,您将获得准备检查的预先计算的数据。
答案 1 :(得分:0)
这样的查询会让您更快地获得结果吗?
SELECT ON.ORDER_NUMBER,
CASE WHEN SET_FOUND.ORDER_NUMBER IS NOT NULL
THEN 'Yes' ELSE 'No' END PROD_FLAG
FROM ORDER ON,
(SELECT ORDER_NUMBER
FROM ORDER_ITEM
WHERE PRODUCT_NAME = 'Mobile'
INTERSECT
SELECT ORDER_NUMBER
FROM ORDER_ITEM
WHERE PRODUCT_NAME = 'PC'
INTERSECT
SELECT ORDER_NUMBER
FROM ORDER_ITEM
WHERE PRODUCT_NAME = 'Tablet') SET_FOUND
WHERE ON.ORDER_NUMBER = SET_FOUND.ORDER_NUMBER (+)
答案 2 :(得分:0)
我的建议是这个:
WITH t AS
(SELECT product_name, order_number
FROM order_item
WHERE product_name IN ('Mobile','PC','Tablet')
GROUP BY order_number, product_name)
SELECT order_number,
CASE WHEN COUNT(DISTINCT product_name) >= 3 THEN 'Yes' ELSE 'No' END
FROM t
JOIN order USING (order_number)
GROUP BY order_number
答案 3 :(得分:0)
订单号是否为递增序列号?如果是这样,一种方法是限制从order_item中选择的数据,你说这是一个大表,通过在order_number上放置条件,你说这是一个索引列。我假设last_run_date显着限制了有关订单的数量。 如果是这样,你可以:
select min(order_number) into order_num_from from Order where order_date>last_run_date
然后进行查询
SELECT order_number,(SELECT CASE WHEN COUNT(DISTINCT product_name)>=3
THEN 'Yes' ELSE 'No' END Prod_Flag
FROM order_item b
WHERE a.order_number=b.order_number
AND b.order_number> order_num_from
AND b.product_name IN ('Mobile','PC','Tablet'))
FROM order a
WHERE order_date>last_run_date;
如果运行速度明显加快(我没有看到解释计划,所以这只是一个如何避免全表扫描的想法),在order_date列上放一个索引并最终使order_num_from进入子查询以获得一个查询。