为了比较,在没有 IN 条件的情况下重写 Oracle 查询/更新
Posted
技术标签:
【中文标题】为了比较,在没有 IN 条件的情况下重写 Oracle 查询/更新【英文标题】:Rewriting Oracle query/update without IN condition for comparison's sake 【发布时间】:2019-07-18 13:29:33 【问题描述】:这里是甲骨文。我有以下表格:
[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
我正在尝试编写一个更新订单并将其状态设置为“已订购”的查询,其中:
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
);
再一次,这个确实工作,但是它很慢所以我想看看是否有一种方法可以在我不使用IN
的情况下重写它以提高效率条件(我在几个地方读到IN
可能导致Oracle 中的性能问题)。有没有什么方法可以在没有IN
的情况下完成重写此查询,以便我可以比较性能?
请注意:在我的特定用例中,更改表格(调整其字段、添加约束/索引/任何内容)是不可能的!
【问题讨论】:
警惕那些告诉您避免使用 SQL 语言的基本元素的来源,例如IN
运算符。它们充其量只是过度概括。
【参考方案1】:
我会开始这样:
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 );
这比您发布的查询要好,原因有几个。
-
它只查看
ORDERS
表一次。
EXISTS
允许
Oracle 停止在相关子查询中查找行
找到一个。
它将order_status = 'PENDING'
条件移动到
主UPDATE
,让优化器更容易实现
它可以使用order_status
上的索引。
如果您没有关于订单状态的索引,请考虑使用一个。确保您使用直方图收集统计信息(如今这主要是自动发生的,具体取决于您拥有的 Oracle 版本)。
为什么直方图很重要?因为您的 order_status
值很可能会出现偏差(即分布不均)。也就是说,人们会期望很多很多订单的状态为“已关闭”或“已订购”或“暂停”(构成这些......),因此其中相对较小的百分比具有“待处理”状态。如果没有直方图,Oracle 将看到的只是一个包含 1,000,000 个值和 4 个不同值的索引——Oracle 不太可能使用这样的索引。直方图为它提供了额外的信息,让您知道,如果您想要“CLOSED”订单,它是一个错误的索引;但如果您想要“待处理”订单,这是一个不错的选择。
【讨论】:
以上是关于为了比较,在没有 IN 条件的情况下重写 Oracle 查询/更新的主要内容,如果未能解决你的问题,请参考以下文章
Django model 遇到查询条件组合比较多的情况下怎么写
为什么重写equals()就必须重写hashCode(),什么情况下可以不重写hashCode()
如何在一组行之后或有条件地在没有 PL/SQL 块的情况下增加 oracle 序列?