简体   繁体   中英

ORACLE SQL INDEX PERFORMANCE

Suppose we have the following query :

select name
from friends
where upper(name) like UPPER('%ESC%') and age = 20;

What is the best way to index it ?

  1. CREATE INDEX fr ON friends (AGE,UPPER(NAME));
  2. CREATE INDEX fr ON friends (AGE);

Thank you.

What is the best way? The two are pretty much equivalent, although the first might have a very small advantage for the query.

At a high level, you can only index age because the like pattern starts with a wildcard. So, Oracle can use the index to find everyone who is the right age when age is the first column of the index.

One wee caveat. Oracle may be smart enough to not apply the upper(name) function if you have the first index, because the value is already in the index. Oracle would still need to scan all the entries in the index for age = 20 , but it would not need to go to the data pages for the where clause. This can be a savings -- but not generally a really big one.

If the query were:

where upper(name) between 'ESC' and 'FSC' and age = 20;

Then the first index would be better because Oracle could directly look up the appropriate rows in the index.

Possibly neither index will help you with this query.

AGE might seem quite selective. There are just over one hundred distinct values (assuming we can rule out trees and buildings as friends). So it might seem that a search on AGE is looking for ~1% of all possible records. However, AGE isn't evenly distributed: a filter on AGE=20 is likely to return way more records than AGE=99 .

As for UPPER(NAME), you're restricting on like UPPER('%ESC%') . CESC would match as would ESCOBAR and FRANCESCA. So the query has to evaluate every name where AGE=20 . If you had an index on friends (AGE,UPPER(NAME)) the whole WHERE clause could be evaluated using an Index Range Scan, which would be reasonably efficient. The index on just AGE would cause a table read at this point.

Either way, the query needs to read the table to get the whole record, because you want to return the NAME not the UPPER(NAME) . If you get a lot of hits on AGE=20 for a common name element that's a lot of indexed reads, which are expensive. A Full Table Scan reading all the whole table could be more efficient unless FRIENDS is an extremely wide table (lots of columns).

Performance tuning is a matter of trade-offs. If you have a lot of records in FRIENDS and a good spread of ages and you want to query on AGE and UPPER(NAME) a lot then an index on friends (AGE,UPPER(NAME)) may be worth the overhead of maintaining it. But if it's a small table or all your friends are of university age then most likely you shouldn't bother with any index.

In short, there's a lot of variables here: all you can do is benchmark the various options and see what works best for you.

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