如何在Oracle 10+中包含NULL的列上使用基于函数的索引?

cle*_*tus 5 sql oracle

让我们假设您在Oracle中有一个表:

CREATE TABLE person (
  id NUMBER PRIMARY KEY,
  given_names VARCHAR2(50),
  surname VARCHAR2(50)
);
Run Code Online (Sandbox Code Playgroud)

使用这些基于函数的索引:

CREATE INDEX idx_person_upper_given_names ON person (UPPER(given_names));
CREATE INDEX idx_person_upper_last_name ON person (UPPER(last_name));
Run Code Online (Sandbox Code Playgroud)

现在,given_names没有NULL值,但为了参数,last_name做了.如果我这样做:

SELECT * FROM person WHERE UPPER(given_names) LIKE 'P%'
Run Code Online (Sandbox Code Playgroud)

解释计划告诉我它使用索引,但将其更改为:

SELECT * FROM person WHERE UPPER(last_name) LIKE 'P%'
Run Code Online (Sandbox Code Playgroud)

它没有.Oracle文档说,只有在满足几个条件时才会使用基于函数的索引,其中一个条件是确保没有NULL值,因为它们没有被索引.

我试过这些问题:

SELECT * FROM person WHERE UPPER(last_name) LIKE 'P%' AND UPPER(last_name) IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

SELECT * FROM person WHERE UPPER(last_name) LIKE 'P%' AND last_name IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,我甚至在last_name上添加了一个索引,但无论我尝试使用全表扫描.假设我无法摆脱NULL值,如何让这个查询使用UPPER(last_name)上的索引?

Ton*_*ews 7

可以使用索引,尽管优化器可能已选择不将其用于特定示例:

SQL> create table my_objects
  2  as select object_id, object_name
  3  from all_objects;

Table created.

SQL> select count(*) from my_objects;
  2  /

  COUNT(*)
----------
     83783


SQL> alter table my_objects modify object_name null;

Table altered.

SQL> update my_objects
  2  set object_name=null
  3  where object_name like 'T%';

1305 rows updated.

SQL> create index my_objects_name on my_objects (lower(object_name));

Index created.

SQL> set autotrace traceonly

SQL> select * from my_objects
  2  where lower(object_name) like 'emp%';

29 rows selected.


Execution Plan
----------------------------------------------------------

------------------------------------------------------------------------------------
| Id  | Operation                   | Name            | Rows  | Bytes | Cost (%CPU)|
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                 |    17 |   510 |   355   (1)|
|   1 |  TABLE ACCESS BY INDEX ROWID| MY_OBJECTS      |    17 |   510 |   355   (1)|
|*  2 |   INDEX RANGE SCAN          | MY_OBJECTS_NAME |   671 |       |     6   (0)|
------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

您阅读的文档可能指出,就像任何其他索引一样,全零键不会存储在索引中.