Wow, you are right on! I did not think of the rank() over. Here is the view:
CREATE OR REPLACE FORCE VIEW TWADMIN.V_INV_CHARTER
(REPAIR_ORD, OLP_CUR_BRANCH, OLP_RECV_BRANCH, SHIP_FROM_FACILITY_ID, SHIP_TO_FACILITY_ID,
SHIP_STATUS, VENDOR_RECV_FACILITY, VENDOR_SHIP_CREATE, USED_OBSOLETE_R_BRANCH, WAS_TRANSFERRED_TO_REPAIR,
PALLET_NBR, RANK)
BEQUEATH DEFINER
AS
SELECT "REPAIR_ORD",
"OLP_CUR_BRANCH",
"OLP_RECV_BRANCH",
"SHIP_FROM_FACILITY_ID",
"SHIP_TO_FACILITY_ID",
"SHIP_STATUS",
"VENDOR_RECV_FACILITY",
"VENDOR_SHIP_CREATE",
"USED_OBSOLETE_R_BRANCH",
"WAS_TRANSFERRED_TO_REPAIR",
"PALLET_NBR",
"RANK"
FROM (SELECT h.repair_ord,
REPLACE (h.curr_facility_id, 'R', '') OLP_CUR_BRANCH,
h.recv_facility_id OLP_RECV_BRANCH,
vvv.ship_from_facility_id,
vvv.ship_to_facility_id,
vvv.ship_status,
vvv.vendor_recv_facility,
vvv.vendor_ship_create,
CASE
WHEN EXISTS
(SELECT 1
FROM twadmin.serial_history
WHERE repair_ord = h.repair_ord
AND curr_facility_id LIKE '%R%')
THEN
1
ELSE
0
END
used_obsolete_r_branch,
CASE
WHEN EXISTS
(SELECT 1
FROM twadmin.serial_history sh
WHERE sh.repair_ord = h.repair_ord
AND sh.curr_facility_id <>
h.recv_facility_id
AND sh.xxxx_status = 'XXXXXXXX')
THEN
1
ELSE
0
END
was_transferred_to_repair,
vvv.pallet_nbr,
RANK ()
OVER (PARTITION BY h.repair_ord
ORDER BY vvv.vendor_ship_create DESC)
RANK
FROM twadmin.ro_hist h
LEFT OUTER JOIN
(SELECT vh.ship_from_facility_id,
vh.ship_to_facility_id,
vh.ship_status,
vh.recv_facility_id vendor_recv_facility,
vd.created_date vendor_ship_create,
vd.repair_ord,
vh.pallet_nbr
FROM twadmin.vendor_ship_dtl vd
INNER JOIN twadmin.vendor_ship_hdr vh
ON vh.pallet_nbr = vd.pallet_nbr) vvv
ON vvv.repair_ord = h.repair_ord)
WHERE RANK = 1;
===============================================================
The query plan seem to be different when the query give specific value vs subquery even if the subquery returns one row:
select /*+ driving_site (i) */*
from twadmin.v_inv_charter@sboptwc i ,priadmin.repair r
where i.repair_ord = r.order_nbr
and r.order_nbr='TW80410857'; <--- This is fast
select /*+ driving_site (i) */ *
from twadmin.v_inv_charter@sboptwc i, priadmin.repair r
where i.repair_ord = r.order_nbr and
r.close_dt > to_date('04/18/2017 00:00:05','MM/DD/YYYY HH24:MI:SS') and
r.close_dt < to_date('04/18/2017 00:00:10','MM/DD/YYYY HH24:MI:SS') <--- This never finished
is there any some fundamental concept that I am just not aware of? Here is the plan:
---------------------------------------------------------------------------------
| Id | Operation | Name |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT REMOTE | |
| 1 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| SERIAL_HISTORY |
| 2 | INDEX RANGE SCAN | SERIAL_HISTORY_REPORD_IDX |
| 3 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| SERIAL_HISTORY |
| 4 | INDEX RANGE SCAN | SERIAL_HISTORY_REPORD_IDX |
| 5 | HASH JOIN | |
| 6 | REMOTE | REPAIR |
| 7 | VIEW | |
| 8 | WINDOW SORT PUSHED RANK | |
| 9 | NESTED LOOPS OUTER | |
| 10 | TABLE ACCESS BY GLOBAL INDEX ROWID | RO_HIST |
| 11 | INDEX UNIQUE SCAN | RO_HIST_PK |
| 12 | VIEW | |
| 13 | NESTED LOOPS | |
| 14 | NESTED LOOPS | |
| 15 | TABLE ACCESS BY INDEX ROWID BATCHED| VENDOR_SHIP_DTL |
| 16 | INDEX RANGE SCAN | VENDOR_SHIP_DTL_REPAIR_ORD |
| 17 | INDEX UNIQUE SCAN | VENDOR_SHIP_HDR_PK |
| 18 | TABLE ACCESS BY INDEX ROWID | VENDOR_SHIP_HDR |
---------------------------------------------------------------------------------
fast vs slow
Plan hash value: 3176346602
--------------------------------------------------------------------------------
| Id | Operation | Name |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT REMOTE | |
| 1 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| SERIAL_HISTORY |
| 2 | INDEX RANGE SCAN | SERIAL_HISTORY_REPORD_IDX |
| 3 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| SERIAL_HISTORY |
| 4 | INDEX RANGE SCAN | SERIAL_HISTORY_REPORD_IDX |
| 5 | MERGE JOIN | |
| 6 | VIEW | |
| 7 | WINDOW SORT PUSHED RANK | |
| 8 | HASH JOIN RIGHT OUTER | |
| 9 | VIEW | |
| 10 | HASH JOIN | |
| 11 | TABLE ACCESS FULL | VENDOR_SHIP_HDR |
| 12 | TABLE ACCESS FULL | VENDOR_SHIP_DTL |
| 13 | PARTITION RANGE ALL | |
| 14 | TABLE ACCESS FULL | RO_HIST |
| 15 | SORT JOIN | |
| 16 | REMOTE | REPAIR |
--------------------------------------------------------------------------------
April 26, 2017 - 4:32 am UTC
Your window function is:
RANK () OVER (PARTITION BY h.repair_ord ORDER BY vvv.vendor_ship_create DESC)
So when your query supplies 'repair_ord' we know that we can push that predicate into the view *without* impacting the result of the rank (because that is *partitioned* by repair_ord anyway).
But if your query predicates do *not* supply repair_ord, we dont *know* if we might return more than 1 repair_ord, which means our RANK function will probably need to examine the whole table (or large subset of it).
If your date range extracts only a *small* number of repair_ord values, you could explore getting a list of them first, and the using each one to drive into the remote view.