Oracle FAQ | Your Portal to the Oracle Knowledge Grid |
![]() |
![]() |
Home -> Community -> Usenet -> c.d.o.server -> Re: SQL tuning
thanks for the reply Jonathan.
--One word of warning - you've made the same mistake that
--Rich Niemiec made in his book in 1999. Your two queries
--are not logically equivalent unless there is a very specific
--uniqueness condition involved.
Can i use replace the EXISTS with an IN like this
SELECT count(*)
FROM asap.task
WHERE ( asap.task.queue_status='N' OR asap.task.queue_status ='C' )
AND asap.task.task_prompt='N' AND asap.task.task_open_ind ='Y' AND asap.task.work_queue_id in
The following is from the Oracle Doc
Use of EXISTS versus IN for Subqueries
In certain circumstances, it is better to use IN rather than EXISTS.
In general, if the selective predicate is in the subquery, then use
IN. If the selective predicate is in the parent query, then use
EXISTS.
See Also:
"How the CBO Executes Anti-Joins"
"HASH_AJ, MERGE_AJ, and NL_AJ" and "HASH_SJ, MERGE_SJ, and NL_SJ"
Oracle9i Data Warehousing Guide
Sometimes, Oracle can rewrite a subquery when used with an IN clause to take advantage of selectivity specified in the subquery. This is most beneficial when the most selective filter appears in the subquery, and when there are indexes on the join columns.
Conversely, using EXISTS is beneficial when the most selective filter is in the parent query. This allows the selective predicates in the parent query to be applied before filtering the rows against the exists criteria.
These are the indexes on the TASK table
TASK FKIDX_TASK_SVCREQPROVPLAN NONUNIQUE TASK FKIDX_TASK_TA_AC_CO_DA NONUNIQUE TASK FKIDX_TA_SE_RE_SI NONUNIQUE TASK FK_TASK_CIRCUIT NONUNIQUE TASK FK_TASK_TASK_TYPE NONUNIQUE TASK IDX_TASK_TASK_NUMBER NONUNIQUE TASK IDX_TASK_TASK_STATUS NONUNIQUE TASK IDX_TASK__REVISED_COMPLETION_D NONUNIQUE TASK IDX_TASK__SCHEDULED_COMPLETION NONUNIQUE TASK IX_TASK_WORK_QUEUE_TASK_OPEN NONUNIQUE TASK IX_TASK_WORK_QUEUE_TASK_STATU2 NONUNIQUE TASK PK_TASK UNIQUE Col umn Pos iti Owner Table name Index Name on Column name
---------- ---------- ------------------------------ ---
-------------------
ASAP TASK FKIDX_TASK_SVCREQPROVPLAN 1 REQ_PLAN_ID ASAP TASK FKIDX_TASK_TA_AC_CO_DA 1 ACTUAL_COMPLETION_D ATE ASAP TASK FKIDX_TA_SE_RE_SI 1 DOCUMENT_NUMBER ASAP TASK FKIDX_TA_SE_RE_SI 2 SERV_ITEM_ID ASAP TASK FK_TASK_CIRCUIT 1 CIRCUIT_DESIGN_ID ASAP TASK FK_TASK_TASK_TYPE 1 TASK_TYPE ASAP TASK IDX_TASK_TASK_NUMBER 1 TASK_NUMBER ASAP TASK IDX_TASK_TASK_STATUS 1 TASK_STATUS ASAP TASK IDX_TASK_TASK_STATUS 2 SYSTEM_TASK_IND ASAP TASK IDX_TASK__REVISED_COMPLETION_D 1 REVISED_COMPLETION_ DATE ASAP TASK IDX_TASK__SCHEDULED_COMPLETION 1 SCHEDULED_COMPLETIO N_DATE ASAP TASK IX_TASK_WORK_QUEUE_TASK_OPEN 1 WORK_QUEUE_ID ASAP TASK IX_TASK_WORK_QUEUE_TASK_OPEN 2 QUEUE_STATUS ASAP TASK IX_TASK_WORK_QUEUE_TASK_OPEN 3 TASK_PROMPT ASAP TASK IX_TASK_WORK_QUEUE_TASK_OPEN 4 TASK_OPEN_IND ASAP TASK IX_TASK_WORK_QUEUE_TASK_STATU2 1 WORK_QUEUE_ID ASAP TASK IX_TASK_WORK_QUEUE_TASK_STATU2 2 TASK_STATUS ASAP TASK PK_TASK 1 DOCUMENT_NUMBER ASAP TASK PK_TASK 2 TASK_NUMBER
19 rows selected.
These are the indexes on WORK_QUEUE table
Table name Index Name UNIQUENES
---------- ------------------------------ ---------
WORK_QUEUE FK_WQ_EMPLOYEE NONUNIQUE WORK_QUEUE FK_WQ_WORK_QUEUE NONUNIQUE WORK_QUEUE PK_WORK_QUEUE UNIQUE Col umn Pos iti Owner Table name Index Name on Column name
---------- ---------- -------------------- --- --------------------
ASAP WORK_QUEUE FK_WQ_EMPLOYEE 1 EMPLOYEE_NUMBER ASAP WORK_QUEUE FK_WQ_WORK_QUEUE 1 PARENT_WORK_QUEUE_ID ASAP WORK_QUEUE PK_WORK_QUEUE 1 WORK_QUEUE_ID
3 rows selected.
select count(*) from work_queue;
COUNT(*)
913
select count(*) from task;
COUNT(*)
2608563
select queue_status,count(*) from task group by queue_status;
Q COUNT(*)
- ----------
B 2 C 419 E 7 G 44439 N 162914 X 19336 2381452
7 rows selected.
select task_prompt,count(*) from task group by task_prompt
T COUNT(*)
- ----------
N 2072523
Y 536046
2 rows selected.
select task_open_ind,count(*) from task group by task_open_ind
T COUNT(*)
- ----------
N 2459644
Y 148925
2 rows selected.
I gather the statistics in a cron job every week. i do it again now
analyze table task compute statistics;
Table analyzed.
analyze table task estimate statistics for columns task_prompt sample 15 percent;
Table analyzed.
analyze table task estimate statistics for columns task_open_ind sample 15 percent;
Table analyzed.
analyze table task estimate statistics for columns queue_status sample
15 perc
ent;
Table analyzed.
the plan is
SELECT count ( *)
FROM task
WHERE ( task.queue_status='N' OR task.queue_status ='C' )
AND task.task_prompt='N'
AND task.task_open_ind ='Y'
AND EXISTS
( SELECT 'X'
FROM work_queue
WHERE work_queue.employee_number =:x
AND work_queue.work_queue_id =task.work_queue_id )
COUNT(*)
0
1 row selected.
Execution Plan
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1633 Card=1 Bytes=10 ) 1 0 SORT (AGGREGATE) 2 1 FILTER 3 2 INDEX (FAST FULL SCAN) OF 'IX_TASK_WORK_QUEUE_TASK_OPE N' (NON-UNIQUE) (Cost=1633 Card=4153 Bytes=41530) 4 2 TABLE ACCESS (BY INDEX ROWID) OF 'WORK_QUEUE' (Cost=2 Card=1 Bytes=16) 5 4 INDEX (UNIQUE SCAN) OF 'PK_WORK_QUEUE' (UNIQUE) (Cos t=1 Card=1)
Statistics
0 recursive calls 20 db block gets 10864 consistent gets 0 physical reads 0 redo size 200 bytes sent via SQL*Net to client 317 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
But if i rewrite the query to this, i get the better plan.
SELECT count(*)
FROM task
WHERE ( task.queue_status='N' OR task.queue_status ='C' )
AND task.task_prompt='N' AND task.task_open_ind ='Y' AND task.work_queue_id in
COUNT(*)
0
1 row selected.
Execution Plan
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=17 Card=1 Bytes=26) 1 0 SORT (AGGREGATE)
2 1 NESTED LOOPS (Cost=17 Card=11224 Bytes=291824) 3 2 TABLE ACCESS (FULL) OF 'WORK_QUEUE' (Cost=2 Card=5 Byt es=80) 4 2 INLIST ITERATOR 5 4 INDEX (RANGE SCAN) OF 'IX_TASK_WORK_QUEUE_TASK_OPEN' (NON-UNIQUE) (Cost=3 Card=83059 Bytes=830590)
Statistics
0 recursive calls 4 db block gets 10 consistent gets 0 physical reads 0 redo size 200 bytes sent via SQL*Net to client 317 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 2 sorts (memory) 0 sorts (disk) 1 rows processed
Your help is very much appreciated.
thanks in advance
srivenu
Received on Thu Apr 10 2003 - 03:56:00 CDT
![]() |
![]() |