I've got this large transaction database that I'm trying to pull data out of. Basically one of the fields in the header table has a '0' in it, and each time I execute this stored procedure, I want to get n number of rows from the header that have a 0, but only those rows that meet some criteria, one of which is that a joined table (indexed, of course) has a matching value to a constant I designate.
Here is the query:
select /*+ FIRST_ROWS(1000)*/ T.ID
from HEADER T
JOIN (
SELECT /*+ parallel(TC,4) FULL(TC) */
tc.ID, tc.SOURCE_ID, tc.CUSTOMER_IDENTIFIER FROM
SUBTABLE tc, (SELECT ID, MAX(IDENT_SEQUENCE_ID) as IDENT_SEQUENCE_ID FROM SUBTABLE
WHERE SOURCE_ID = 9002 AND upper(trim(CUSTOMER_IDENTIFIER)) <> 'UNKNOWN' GROUP BY ID) maxtc
WHERE maxtc.ID = tc.ID AND
maxtc.CUST_IDENT_SEQUENCE_ID = tc.CUST_IDENT_SEQUENCE_ID
) cust
ON t.ID = cust.ID
where T.batch=0 and T.status=6 and rownum <= SOME_NUMBER_HERE;
I was hoping the "FIRST_ROWS" or the rownum limit would make this basically just look for the first "SOME_NUMBER_HERE" number of records and return, but instead it seems Oracle is scanning the whole table?
Anyway to make it run faster, by stopping the select statement inside the join, after finding a certain number of matching rows?
I've got indexes on CUSTOMER_IDENTIFIER & SOURCE_ID on the SUBTABLE, and BATCH/STATUS on the HEADER.
This seems to run sub-second when I've got a hundred thousand rows, but takes several minutes when running on multi-millions rows... Thanks in advance for any assistance...
The following recommendations will help you in your SQL tuning process.
You'll find 3 sections below:
SELECT
T.ID
FROM
HEADER T
JOIN
(
SELECT
tc.ID,
tc.SOURCE_ID,
tc.CUSTOMER_IDENTIFIER
FROM
SUBTABLE tc,
(SELECT
SUBTABLE.ID,
MAX(IDENT_SEQUENCE_ID) AS IDENT_SEQUENCE_ID
FROM
SUBTABLE
WHERE
SUBTABLE.SOURCE_ID = 9002
AND upper(trim(SUBTABLE.CUSTOMER_IDENTIFIER)) <> 'UNKNOWN'
GROUP BY
SUBTABLE.ID) maxtc
WHERE
maxtc.ID = tc.ID
AND maxtc.CUST_IDENT_SEQUENCE_ID = tc.CUST_IDENT_SEQUENCE_ID
) cust
ON t.ID = cust.ID
WHERE
T.batch = 0
AND T.status = 6
AND rownum <= SOME_NUMBER_HERE