I was happily using function based indices to provide case insensitivity like so:
CREATE UNIQUE INDEX MyIndexName ON MyTable (
LOWER (SomeColumn) ASC
);
Worked like a charm. The uniques was case insensitive and the normal query like:
SELECT blah, foo, bar
FROM MyTable
WHERE LOWER(SomeColumn) = LOWER (:bindparam);
was happily using the index.
Until one day at (naturally) a client site, one of my fellow engineers found that the above query was performing a full table scan. And, despite what Tom Kite keeps saying, in this case, a full table scan is bad.
Only after some spelunking through Tom's Book Expert One-on-One Oracle did I find the magic. The database needs the following session/system variables in place to actually use the function-based indices:
QUERY_REWRITE_ENABLED=TRUE
QUERY_REWRITE_INTEGRITY=TRUSTED
I'll chock these up to the huge pile of stuff that "Oracle needs to have to work the way it should but is next to impossible to find unless you already know it."
Hopefully this saves someone else some time.
[Listening to: Tripping Daisy - Piranha]