为比较起见,不使用IN条件重写Oracle查询/更新

时间:2019-07-18 13:29:33

标签: sql oracle performance query-optimization

Oracle在这里。我有以下表格:

[orders]
===
order_id : integer constraint pk_orders primary key using index
order_name : varchar2(40 char)
order_ordered_by : integer constraint fk_shoppers references accounts
order_total : number(10,2) not null
order_status : char not null

[line_items]
===
line_item_id : integer constraint pk_line_items primary key using index
order_id : integer not null constraint fk_line_items_orders references orders on delete cascade
product_id : integer not null constraint fk_line_items_products references products
line_item_quantity : integer not null

[products]
===
product_id : integer constraint pk_products primary key using index
product_name : varchar2(40 char)
product_category : varchar2(10 char)
product_available_on : date

我试图编写一个查询来更新订单并将其状态设置为“ ORDERED”,其中:

  • orders.order_status当前处于“待处理”状态;和
  • products.product_category当前为“ COFFEE”;和
  • products.product_available_on当前小于或等于当前时间(现在)

到目前为止我最大的努力能成功并完成工作:

UPDATE orders
SET status = 'ORDERED'
WHERE order_id IN (
    SELECT DISTINCT orders.order_id
    FROM orders
    INNER JOIN line_items ON line_items.orderId = orders.order_id
    INNER JOIN products ON line_items.product_id = products.product_id
    WHERE
        orders.status = 'PENDING' AND
        products.product_category = 'COFFEE' AND
        products.product_available_on <= CURRENT_DATE
);

同样,此确实有效,但是它相当慢,所以我尝试查看是否有一种方法可以在不使用{{1 }}条件(我在多个地方读过IN可能导致Oracle性能问题)。没有IN,有什么方法可以完成重写此查询,以便我可以比较性能吗?

请注意::在我的特定用例中,更改表(调整其字段,添加约束/索引/任何内容)是不可能的!

1 个答案:

答案 0 :(得分:3)

我会开始

UPDATE orders o
SET    o.status = 'ORDERED'
WHERE  o.status = 'PENDING'
AND    EXISTS ( SELECT 'line for available coffee'
                FROM   line_items li
                INNER JOIN products p ON p.product_id = li.product_id
                WHERE  li.order_id = o.order_id
                AND    p.product_category = 'COFFEE'
                AND    p.product_available_on <= SYSDATE );

由于某些原因,这比您发布的查询要好。

  1. 它仅查看ORDERS表一次。
  2. EXISTS允许 Oracle停止在相关子查询中查找行之一 找到一个。
  3. 它将order_status = 'PENDING'条件移动到 主UPDATE,使优化程序更容易实现 它可以使用order_status上的索引。

如果您没有关于订单状态的索引,请考虑一个。确保您使用直方图收集统计信息(如今这通常会自动发生,具体取决于您所使用的Oracle版本)。

为什么直方图很重要?因为您的order_status值很可能会偏斜(即分布不均匀)。就是说,人们会期望状态为“已关闭”或“已下订单”或“处于保留状态”的许多订单(正在补货...),因此,相对少部分订单的状态为“待处理”。如果没有直方图,Oracle将看到的只有一个具有1,000,000个值和4个不同值的索引-Oracle不太可能使用这样的索引。直方图为它提供了额外的信息,以了解如果您想要“已平仓”的订单,它一个不好的索引;但是如果您要“待定”订单,那是一个很好的订单。