简体   繁体   中英

Oracle SQL - Select not using index as expected

So I haven't used Oracle in more than 5 years and I'm out of practice. I've been on SQL Server all that time.

I'm looking at some of the existing queries and trying to improve them, but they're reacting really weirdly. According to the explain plan instead of going faster they're instead doing full table scans and not using the indexes.

In the original query, there is an equijoin done between two tables done in the where statement. We'll call them table A and B. I used an explain plan followed by SELECT * FROM table(DBMS_XPLAN.DISPLAY (FORMAT=>'ALL +OUTLINE')); and it tells me that Table A is queried by Local Index.
TABLE ACCESS BY LOCAL INDEX ROWID

SELECT A.* 
FROM TableA  A, TableB B 
WHERE A.SecondaryID = B.ID;

I tried to change the query and join TableA with a new table (Table C). Table C is a subset of Table B with 700 records instead of 100K. However the explain plan tells me that Table A is now queried with a full lookup.

CREATE TableC 
AS<br>
SELECT * FROM TableB WHERE Active='Y';



SELECT A.* 
FROM TableA  A, TableC C 
WHERE A.SecondaryID = C.ID;

Next step, I kept the join between tables A & C, but used a hint to tell it to use the index on Table A. However it still does a full lookup.

SELECT /*+ INDEX (A_NDX01) */ A.* 
FROM TableA  A, TableC C 
WHERE A.SecondaryID = C.ID;

So I tried to change from a join to a simple Select of table A and use an IN statement to compare to table C. Still a full table scan.

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC);

Lastly, I took the previous statement and changed the subselect to pull the top 1000 records, and it used the index. The odd thing is that there are only 700 records in Table C.

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC WHERE rownum <1000

)

I was wondering if someone could help me figure out what's happening?
My best guess is that since TableC is a new table, maybe the optimizer doesn't know how many records are in it and that's why it's it will only use the index if it knows that there are fewer than 1000 records?
I tried to run dbms_stats.gather_schema_stats on my schema though and it did not help.
Thank you for your help.

As a general rule Using an index will not necessarily make your query go faster ALWAYS.

Hints are directives to the optimizer to make use of the path, it doenst mean optimizer would choose to obey the hint directive. In this case, the optimizer would have considered that an index lookup on TableA is more expensive in the

SELECT A.* 
FROM TableA  A, TableB B 
WHERE A.SecondaryID = B.ID;

SELECT /*+ INDEX (A_NDX01) */ A.* 
FROM TableA  A, TableC C 
WHERE A.SecondaryID = C.ID;

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC);

Internally it might have converted all of these statements(IN) into a join which when considering the data in the tableA and tableC decided to make use of full table scan.

When you did the rownum condition, this plan conversion was not done. This is because view-merging will not work when it has the rownum in the query block.

I believe this is what is happening when you did

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC WHERE rownum <1000)

Have a look at the following link

Oracle. Preventing merge subquery and main query conditions

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM