此问题在此处已有答案:
Subquery function invoked twice if alias is used in main SQL(2个答案)
How to prevent Oracle from calling a function for every attribute of the function result(1个答案)
昨天关门了。
我有一个这样的Oracle SQL查询,它需要44秒运行。
select shipment_id, Shipment_Flow_API.Get_Next_Step(SHIPMENT_ID) Shipment_flow
from shipment_line_ovw
where
SHIPMENT_STATE = 'Preliminary'
and Shipment_Flow_API.Get_Next_Step(SHIPMENT_ID) = 'Report picking, Print pick list'
如果我把最后一行取出来,像这样做,只需要0.43秒,就可以返回大约100条记录。
select shipment_id, Shipment_Flow_API.Get_Next_Step(SHIPMENT_ID) Shipment_flow
from shipment_line_ovw
where
SHIPMENT_STATE = 'Preliminary'
我在想,如果我试着把上面的一个cte或一个100条记录的子查询,然后在之后的shipping flow列上进行过滤,它应该运行得很快,就像下面一样。但是oracle引擎仍然试图从原始表中重新选择并按所有记录进行过滤,所以它仍然需要40多秒
with cte as (
select
shipment_id, Shipment_Flow_API.Get_Next_Step(SHIPMENT_ID) Shipment_flow
from shipment_line_ovw
where
SHIPMENT_STATE = 'Preliminary'
)
select * from cte
where Shipment_flow = 'Report picking, Print pick list';
如何在过滤之前将其作为内存中的一组记录,以便运行得更快?
2条答案
按热度按时间lyfkaqu11#
我明白了。可以把记忆中的记录变成这样。
这样跑得快多了,0.73秒。
在这个问题的答案的帮助下弄明白了,尽管原来的问题和我的略有不同。
How do you create a temporary table in an Oracle database?
gywdnpxw2#
Oracle很可能在计算
SHIPMENT_STATE
predicate 之前执行了该函数,而您的函数相当慢。通过具体化CTE,您首先强制计算SHIPMENT_STATE
predicate ,这肯定大大减少了函数计算的候选行。您可以使用带有NO_MERGE
提示的常规内联查询块执行相同的操作。或者,如果这是一个视图,在一个块中添加或减少一个 predicate 可能会显著地改变视图的执行计划,即使是以您意想不到的方式。然而,最快的方法不是这两个选项。相反,使用函数创建虚拟列,然后索引它。如果
shipment_line_ovw
是一个表:然后简单地说:
但是,如果
shipment_line_ovw
实际上是一个视图,那么您可能希望将虚拟列添加到底层基表并在视图中暴露next_step
。如果您有任何排序,则可能需要进行一些返工以使 predicate 在视图中下推。但这是可行的。因此,最好直接查询表而不是视图。